gpt4 book ai didi

在C中将纬度和经度转换为 float

转载 作者:行者123 更新时间:2023-11-30 14:49:06 24 4
gpt4 key购买 nike

我正在尝试将纬度和经度坐标转换为小数点后 4 位 float 。我有“工作”代码,但它只是有点偏离,比如 %50 的时间。任何人都可以帮助我或有更好的设计以使其更精确吗?

 float sexag2decimal(char * deg){
char *sdeg = malloc(sizeof(char)*3);
char *smin = malloc(sizeof(char)*3);
char *ssec = malloc(sizeof(char)*3);
char *ssec2 = malloc(sizeof(char)*5);
int size = strlen(deg);
int m = 0;
for(m = 0; m < size-1; m++){
if(deg[m] >= 65 && deg[m] <= 122){
return 0;
}
}
float converted = 0;
if(deg[0] == '0'){
strcpy(&sdeg[0], &deg[1]);
strcpy(&sdeg[1], &deg[2]);
strcpy(&smin[0], &deg[4]);
strcpy(&smin[1], &deg[5]);
strcpy(&ssec[0], &deg[7]);
strcpy(&ssec[1], &deg[8]);
strcpy(&ssec2[0], &deg[10]);
strcpy(&ssec2[1], &deg[11]);
strcpy(&ssec2[2], &deg[12]);
strcpy(&ssec2[3], &deg[13]);
}else{
if(deg[14] == 'W')
return 0;
strcpy(&sdeg[0], &deg[0]);
strcpy(&sdeg[1], &deg[1]);
strcpy(&smin[0], &deg[3]);
strcpy(&smin[1], &deg[4]);
strcpy(&ssec[0], &deg[6]);
strcpy(&ssec[1], &deg[7]);
strcpy(&ssec2[0], &deg[9]);
strcpy(&ssec2[1], &deg[10]);
strcpy(&ssec2[2], &deg[11]);
strcpy(&ssec2[3], &deg[12]);
}
sdeg[2] = '\0';
smin[2] = '\0';
ssec[2] = '\0';
ssec2[4] = '\0';
converted = atoi(sdeg) + ((float)atoi(smin)/60.0) + (((float)atoi(ssec)+((float)atoi(ssec2))/10000)/3600.0);
free(sdeg);
free(smin);
free(ssec);
free(ssec2);
return converted;
}

谢谢!

输入:

30-25-30.7140N,086-53-37.8590W

29-57-33.3000N,081-20-23.0000W

我的输出:

30.4252,-86.8939

29.9592,-81.3397

正确输出:

30.4252,-86.8938

29.9593,-81.3397

谢谢!

最佳答案

OP 的代码因尝试在分配的缓冲区之外写入而受到影响。 @cyclaminist

float sexag2decimal(char * deg){
char *sdeg = malloc(sizeof(char)*3); // Too small for the entire string
...
strcpy(&sdeg[0], &deg[0]); // UB: attempts to copy the _entire_ string to `deg`

当然OP意味着编写类似的代码

    // strcpy(&sdeg[0], &deg[0]);
sdeg[0] = deg[0]; // Copy 1 char
<小时/>

it's just a bit off like %50 of the time

鉴于 OP 的代码在上述 UB 中幸存下来,观察到的输出与预期不同,部分原因是计算中累积舍入的结果:

converted = atoi(sdeg) + ((float)atoi(smin)/60.0) + 
(((float)atoi(ssec)+((float)atoi(ssec2))/10000)/3600.0);

这会导致(float)atoi(smin)/60.0(float)atoi(ssec2))/10000)(float)atoi四舍五入(ssec2))/10000)/3600.0) 以及 3 个添加中的每一个。

使用更高精度的数学,例如double而不是float,将显着减少舍入效应,但不能消除它们

为了提高准确性,请使用整数数学进行不舍入的计算。角度的预期值(以万分之一秒为单位)大约需要 36 位数学运算。

long seconds = ((atoi(sdeg) * 60) + atoi(smin)) * 60 + atoi(ssec);
long myriad_seconds = (seconds * 10000) + atoi(ssec2);
<小时/>

... to 4 decimal place float

这个目标有些矛盾。 float 通常采用二进制编码,因此不会产生十进制。听起来 OP 确实想将一些 float 打印到小数点后 4 位。为此,代码需要进行额外的舍入。

将精确的 myriad_seconds 转换为 float 会产生舍入误差。

// "29-57-33.3000N"
// myriad_seconds = 1078533000
// With infinite math, the quotient is 29.95925
float converted = myriad_seconds/(60.0f * 60 * 10000);
// The "best" `float` is just less than 29.95925
// converted = 29.959249777...

浮点转换为小数点后4位文本会产生另一个舍入错误。

printf("%.4f\n", converted);
// "29.9592"

如果这是OP的目标,那么像这段代码那样执行更少的舍入,会大大提高,但不会消除“偶尔”的情况。

<小时/>

此任务的发起者巧妙地选择了接近 xxx.xxxx5... 的最终值。这些值对“稍微偏离”的计算路径很敏感。

为了对抗这种狡猾行为,请考虑返回一个 10,000 度数的整数,而不是返回一个 float 。通过无错误/舍入 myriad_seconds 和受控舍入到 myriad_ Degrees,代码将始终达到预期的答案 - 但代价是源代码更加复杂。

// Add signed half of 3600 to effect rounding (half way away from zero) before division.
long myriad_degrees = (myriad_seconds + (myriad_seconds < 0 ? -1 : 1) * 3600 / 2) / 3600;

printf("%s%ld.%04ld\n", myriad_degrees < 0 ? "-" : "",
labs(myriad_degrees) / 10000, labs(myriad_degrees) % 10000);

// Output
29.9593

关于在C中将纬度和经度转换为 float ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49956694/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com