1

下面我的 C 代码中发生了一些奇怪的事情。

我想比较数字,我四舍五入到小数点后 4 位。

我已经调试过了,可以看到传入的数据。

的值为tmp_ptr->current_longitude6722.31500000, 的值为tmp_ptr->current_latitude930.0876500000。

使用 sprintf 语句后:

charTmpPtrXPos = "6722.3150" and charTmpPtrYPos = "930.0876".

我希望 speed_info->myXPos 和 speed_info->myYPos 的结果完全相同,但奇怪的是,sprintf 语句speed_info->myXPos = 6722.31500000的值speed_info->myYPos > = 30.0876500000

charSpeedPtrYPos= "930.0877"

所以基本上 sprintf 语句对于第二个值的行为不同,并且似乎将其四舍五入。经过调试,我知道 sprintf 语句的输入是完全相同的。

谁能想到这其中的原因?

sizeOfSpeedList = op_prg_list_size (global_speed_trajectory);

tmp_ptr= (WsqT_Location_Message*)op_prg_mem_alloc(sizeof(WsqT_Location_Message));
tmp_ptr = mbls_convert_lat_long_to_xy (own_node_objid);

sprintf(charTmpPtrXPos, "%0.4lf", tmp_ptr->current_longitude);
sprintf(charTmpPtrYPos, "%0.4lf", tmp_ptr->current_latitude);

speed_info = (SpeedInformation *) op_prg_mem_alloc (sizeof (SpeedInformation));
for (count=0; count<sizeOfSpeedList; count++)
{
    speed_info = (SpeedInformation*) op_prg_list_access (global_speed_trajectory, count);

    sprintf(charSpeedPtrXPos, "%0.4lf", speed_info->myXPos);
    sprintf(charSpeedPtrYPos, "%0.4lf", speed_info->myYPos);

    //if((tmp_ptr->current_longitude == speed_info->myXPos) && (tmp_ptr->current_latitude == speed_info->myYPos))
    if ((strcmp(charTmpPtrXPos, charSpeedPtrXPos) == 0) && (strcmp(charTmpPtrYPos, charSpeedPtrYPos) == 0))
    {
        my_speed = speed_info->speed;
        break;
    }
}
4

3 回答 3

4

printf()通常四舍五入到最接近的十进制表示,并发送到“偶数”(即,最后一位数字为 0、2、4、6 或 8 的表示)。

但是,您必须了解大多数可以用十进制有限表示的数字不能用二进制浮点有限表示。例如,实数930.08765不能表示为二进制浮点数。您真正拥有的值(以及转换为十进制的值)是另一个数字,double很可能略高于。这个数字被四舍五入到十进制表示是正常的,因为它更接近这个表示而不是。930.08765930.0876500000000532963895238935947418212890625930.0877930.0876


请注意,如果您使用的是 Visual Studio,您的 *printf() 函数可能会被限制为显示 17 个有效数字,从而阻止您观察double最近的930.08765.

于 2013-08-09T14:06:21.533 回答
2

float这是 a和 a之间的区别double

OP 很可能使用tmp_ptr->current_latitudeas afloatspeed_info->myYPosas a double。除非double空间/速度要求使用float.

int main() {
  float  f1 = 930.08765;
  double d1 = 930.08765;
  printf("float  %0.4f\ndouble %0.4f\n", f1, d1);
  return 0;
}

float  930.0876  
double 930.0877

由于典型float使用 IEEE 4 字节二进制浮点表示,f1因此采用 930.087646484375 的精确值
930.0876
(这是 4 位打印结果)
这是最接近float930.08765 的值。

同样,对于 a double,取 930.0876500000000532963895238935947418212890625 930.0877d1的确切值 (这是 4 位打印结果)

一般来说,可以使用更多的小数位来减少其他数字发生这种情况的可能性,但不能消除它。


候选快速修复

sprintf(charSpeedPtrYPos, "%0.4lf", (float) speed_info->myYPos);

这将首先将值从转换speed_info->myYPos为 a float。由于 type 的非原型参数在传递给 之前被float转换为,因此该值将被转换回. 最终结果是数字精度损失,但字符串转换结果相同。doublesprintf()double

printf("(float) double  %0.4f\n", (float) d1);
// (float) double  930.0876

顺便说一句:lin"%0.4lf"没有代码生成目的。虽然是允许的。

于 2013-08-09T14:52:09.557 回答
0

见:http ://www.cplusplus.com/reference/cstdio/printf/

一个点后跟一个数字指定精度,在您的情况下为 4。如果需要,请尝试使用更高的精度。我已经以 5 的精度尝试了你的数字,它不再四舍五入了。所以应该是..

sprintf(charSpeedPtrYPos, "%0.5lf", speed_info->myYPos);

..或任何适合您需要的更高数字。

于 2013-08-09T13:57:16.377 回答