sprintf似乎正在四舍五入?

时间:2013-08-09 13:43:08

标签: c printf

我的C代码中出现了奇怪的事情。

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

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

tmp_ptr->current_longitude的值为6722.31500000,tmp_ptr->current_latitude的值为930.0876500000。

使用sprintf语句后:

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

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

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;
    }
}

3 个答案:

答案 0 :(得分:4)

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

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


请注意,如果您使用的是Visual Studio,则* printf()函数可能会限制为显示17位有效数字,从而使您无法观察double最近930.08765的确切值。

答案 1 :(得分:2)

这是floatdouble之间的差异。

OP可能会将tmp_ptr->current_latitude用作float而将speed_info->myYPos用作double。除非空格/速度强制使用double,否则建议OP使用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位数的打印结果)
这是与930.08765最接近的float值。

同样地,对于doubled1具有确切的值 930.0876500000000532963895238935947418212890625
930.0877(这是4位数的打印结果)

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


候选人快速解决方案

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

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

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

BTW:l中的"%0.4lf"没有代码生成目的。但是允许这样做。

答案 2 :(得分:0)

请参阅:http://www.cplusplus.com/reference/cstdio/printf/

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

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

..或任何符合您需求的更高数字。