7-1 求赤道上两点的球面距离 分数 10 全屏浏览 作者 巨同升 单位 山东理工大学 已知地球的赤道半径为6378.137千米,并已知东半球赤道上两点的经度(单位为度),编写程序计算这两点之间的球面距离是多少千米。要求所有的实数使用double类型,圆周率的近似值取3.141592653589793。 提示:赤道上两点之间的球面距离,就是赤道上两点之间劣弧的长度。 输入格式: 在一行中输入两个代表经度的非负实数,以空格分隔。 输出格式: 输出球面距离的值,保留3位小数,最后换行。
时间: 2025-07-12 09:34:33 浏览: 6
<think>嗯,我现在要解决这个问题,题目是求赤道上两点的球面距离。首先,我得仔细理解题目要求。题目给出赤道的半径是6378.137千米,输入是两个东半球的经度值,要计算这两点之间的球面距离,也就是赤道上的劣弧长度。输出要保留三位小数。
首先,赤道是一个圆,半径为R=6378.137。两点在赤道上,所以它们的纬度都是0度,经度分别是给定的两个值。那么这两点在赤道圆上的距离就是沿着圆弧的最短路径,也就是劣弧的长度。这应该等于圆心角(弧度)乘以半径。
那如何计算这两个经度之间的圆心角呢?这里需要注意经度的范围。东半球的经度范围是东经0度到东经180度吗?或者题目中的“东半球”可能指的是东经的范围,比如可能题目中的两个经度都是东经,比如东经0到180之间。那输入的经度应该是在东半球,所以可能都是0到180之间的数值?
不过不管东半球的具体定义,题目给出的两个经度值都是东半球的,所以它们的经度应该是在同一半球,不需要考虑跨越东西半球的情况。但具体计算的时候,可能需要先计算两者的经度差,然后取绝对值,再考虑是否要转成较小的那个圆心角。比如,如果两个点的经度差是350度,那么实际的最短圆心角应该是10度,因为360-350=10。所以这个时候应该取两者的差的绝对值和360减去该绝对值的较小值。
所以步骤应该是:
1. 读取两个经度值,设为A和B。
2. 计算它们的经度差Δλ = |A - B|。
3. 因为经度是环形的,360度一个周期,所以实际的有效差值是min(Δλ, 360 - Δλ)。但题目中给出的是东半球的点,所以可能输入的经度都是0到180之间的,所以两者的差值不会超过180度?或者可能输入的两个经度可能超过东半球的范围?这点需要仔细看题目。题目描述中说“东半球赤道上的两点”,所以可能这里的东半球指的是经度范围是东经0度到东经180度?或者可能题目中的东半球是指东经的范围,所以输入的经度可能在0到180度之间?
但不管怎样,正确的处理方式是计算它们的差值,然后取绝对值,然后取360度中的最短弧度。例如,如果两点经度差是200度,那么实际圆心角应该是160度,因为200度比360-200=160大,所以取较小的那个。所以正确的做法是取Δ = |A - B|,然后如果Δ>180,则取360 - Δ作为实际的圆心角度数差。否则取Δ。
比如,A是10度,B是350度,那么Δ=340度,但实际圆心角是20度。这时候正确的差是20度。所以正确的处理方式是差值Δ = |A - B| % 360,然后如果Δ >180,则取360-Δ,否则取Δ。或者等价于取min(Δ, 360 - Δ)。
但是题目中的输入是否允许超过360度的经度?比如输入的经度可能是400度这样的?题目中说“经度的非负实数”,所以有可能输入的数据大于360。这时应该先对经度进行取模,转化为0到360之间的数值。例如,400度的话模360得到40度。所以处理输入的经度时,应该先取模360,确保在0到360范围内。然后再计算两者的经度差。
所以步骤应该是:
1. 输入两个经度值,假设为lon1和lon2。
2. 将lon1和lon2转换为0-360之间的数值,通过取模360。例如,lon1 = lon1 % 360,lon2同理。
3. 计算两者的差值的绝对值Δ = |lon1 - lon2|。
4. 如果Δ > 180度,那么实际的圆心角是360 - Δ。否则,就是Δ。
5. 这样得到的圆心角是度数,需要转换为弧度,乘以π/180。
6. 球面距离就是R * θ(弧度)。
所以现在需要考虑如何处理输入的数据。例如,输入的两个经度是否可能大于360?比如输入370度,则模360后是10度。所以不管输入的是什么,先模360处理,再计算差值。
比如,输入的两个经度是10和350,模后还是10和350。差值是340,大于180,所以实际圆心角是20度。转换成弧度是20 * π / 180 = π/9。球面距离是R * π/9。
那现在,需要将这些步骤用代码实现。
代码的大致流程:
读取输入的两个double数值,lon1和lon2。
处理lon1和lon2,取模360:
lon1 = lon1 % 360.0;
lon2 = lon2 % 360.0;
然后计算Δ = abs(lon1 - lon2)。如果Δ > 180,则θ = 360 - Δ;否则θ = Δ。
将θ转换为弧度:theta_rad = θ * π / 180.0;
球面距离distance = R * theta_rad。
然后输出保留三位小数。
但是这里需要注意,当两个经度差正好是180度时,这时候圆心角是180度,此时球面距离是半圆周长,即πR。
例如,输入的两个经度是0和180,处理后差值是180,所以圆心角是180度,转换为弧度是π,距离是R*π。
那现在,如何实现这个逻辑?
在代码中,可以用:
delta = fabs(lon1_processed - lon2_processed);
if (delta > 180.0) {
delta = 360.0 - delta;
}
theta = delta;
theta_rad = theta * PI / 180.0;
distance = R * theta_rad;
这样是否正确?
是的。例如,当delta是200,那么delta会被修正为160,即正确的圆心角。如果是340,修正为20。如果是180,则保持180,这样计算出来的距离是半圆周长。
那现在,如何处理输入的lon1和lon2的取模?例如,对于负数的情况,题目中说输入的是非负实数。所以无需处理负数的情况。但是输入的可能例如是450度,模360后是90度。
在C++中,取模运算对浮点数的处理可能需要用fmod函数。例如,lon1的处理可以用fmod(lon1, 360.0)。但需要注意,当输入的是负数时,fmod的结果可能为负,但题目中的输入是非负实数,所以不需要处理这种情况。
例如,输入的是370,fmod(370, 360)=10.0;输入的是720,fmod(720, 360)=0.0。输入的是30,fmod(30, 360)=30.0。所以正确。
所以代码中的处理步骤:
lon1 = fmod(lon1_input, 360.0);
lon2 = fmod(lon2_input, 360.0);
这样,确保两者的经度都在0到360度之间。
那么现在,整个逻辑是正确的。
现在,代码的大致结构:
#include <stdio.h>
#include <math.h>
int main() {
double lon1, lon2;
scanf("%lf %lf", &lon1, &lon2);
const double R = 6378.137;
const double PI = 3.141592653589793;
// 处理经度到0-360之间
lon1 = fmod(lon1, 360.0);
lon2 = fmod(lon2, 360.0);
double delta = fabs(lon1 - lon2);
if (delta > 180.0) {
delta = 360.0 - delta;
}
double theta_rad = delta * PI / 180.0;
double distance = R * theta_rad;
printf("%.3f\n", distance);
return 0;
}
那这个代码是否正确?
测试几个例子:
比如,输入0 0,输出0.000。
输入0 180,delta是180,不调整,theta_rad=π,距离R*π=6378.137*3.141592653589793≈20037.557(大约)。但实际计算的话:
6378.137 * 3.141592653589793 ≈ ?
用计算器计算:6378.137 * π ≈ 6378.137 *3.141592653589793=20037.557 km。这应该是半圆周长,所以正确。
另一个例子,输入0和90度,差90度,转换为弧度是π/2,距离是R*(π/2)=6378.137*1.5708≈10018.77 km。保留三位小数是10018.778?
或者更精确计算的话:
6378.137 * (90 * 3.141592653589793 / 180) = 6378.137 * 1.5707963267948966 ≈ 6378.137 * 1.5707963267948966 =
6378.137 × 1.5707963267948966 ≈
6378.137 × 1.5707963267948966 ≈
6378.137 × 1.5707963267948966:
先计算 6000*1.5707963267948966= 9424.7779607683778
378.137 ×1.5707963267948966≈ 378.137 ×1.5708≈ 378.137 ×1.5=567.2055, 378.137×0.0708≈26.79,总和约593.9955。总和总的是9424.7779+593.9955≈10018.7734,所以三位小数是10018.773,输出10018.773。
那程序会正确输出。
另一个测试案例,输入的两个经度是350和10。处理后的经度是350和10,差是340。因为340>180,所以delta=20度。转换为弧度是20 * π/180 = π/9 ≈0.349066 radians。距离是6378.137 ×0.349066≈ 6378.137×0.349066≈2225.263。三位小数是2225.263。
程序是否正确处理这种情况?
是的,因为输入350和10会被处理为350和10,差是340,大于180,所以delta=20度。然后计算正确。
另一个情况,输入的是370度和730度。370模360是10度,730模360是730-2*360=730-720=10度。所以两者都是10度,差为0,距离0。
所以程序正确处理。
那现在,代码应该没有问题。需要注意,题目中的输入是东半球的经度,但是根据题目中的处理,输入的两个经度可以是任何非负实数,但处理后的经度可能超出东半球的范围?比如,输入的是200度,那处理后是200度,属于东半球吗?
题目中说东半球的两点,所以可能输入的两个经度都在东半球范围内。但题目可能并不检查输入是否符合,而只是假设输入的是东半球的经度。但根据题目中的描述,用户输入的是东半球赤道上的两点的经度,所以输入的两个值可能在0到180之间?或者题目中的东半球是否指东经0到东经180?
假设题目中的东半球是指东经范围,所以输入的经度应该在0到180度之间。因此,当处理后的经度可能超过180时,比如输入的是190度,模360之后是190,可能属于西半球?
但题目中给出的输入是否可能超出东半球范围?题目描述中说“东半球赤道上的两点”,所以输入的经度应该已经属于东半球。但程序是否需要进行检查?题目中的输入格式描述中并没有限制,所以用户可能输入任何非负实数,但程序需要按照正确的数学处理,不管是否属于东半球。
例如,输入的经度可能是东半球的,如0到180度。比如,输入两个经度分别是30和150,差120度,正确计算。如果输入的是东经200度,这实际上是西经160度(因为200-180=20,所以东经200度属于西半球?或者东半球的定义是否是0到东经160?这可能要看题目的定义。但题目中可能认为东半球的范围是东经0到东经180度,所以输入的经度可能在0到180之间。但根据题目中的提示,程序不需要处理这种情况,只需要正确计算两者的经度差,不管是否属于东半球。所以程序无需判断输入是否属于东半球,而是直接计算即可。
综上,代码是正确的。</think>要计算赤道上两点的球面距离,需按以下步骤进行:
### 分析步骤
1. **理解问题**:赤道为圆,半径已知。两点经度差决定圆心角,球面距离即劣弧长度(弧长=半径×圆心角弧度)。
2. **处理经度**:
- 将输入经度转换为0-360度内的等效值(如370度→10度)。
- 计算经度差的绝对值,若超过180度,取360度补数(如200度差→160度)。
3. **转换为弧度**:角度差乘以π/180。
4. **计算弧长**:半径乘以弧度。
### 代码实现
```c
#include <stdio.h>
#include <math.h>
int main() {
double lon1, lon2;
scanf("%lf %lf", &lon1, &lon2);
const double R = 6378.137;
const double PI = 3.141592653589793;
// 调整经度到0-360范围内
lon1 = fmod(lon1, 360.0);
lon2 = fmod(lon2, 360.0);
double delta = fabs(lon1 - lon2);
if (delta > 180.0) {
delta = 360.0 - delta;
}
double distance = R * delta * PI / 180.0;
printf("%.3f\n", distance);
return 0;
}
```
### 代码解释
- **输入处理**:使用`fmod`确保经度在0-360度内。
- **经度差计算**:取绝对值后,若超过180度则取其补数。
- **弧长计算**:圆心角转为弧度后,乘以半径得到距离。
- **输出**:保留三位小数。
此方法确保正确计算赤道上任意两点的最短球面距离。
阅读全文
相关推荐














