user2051005
user2051005

Reputation: 21

sprintf seems to be rounding up?

Something odd is occuring in my C code below.

I want to compare numbers and I round to 4 decimal places.

I have debugged and can see the data being passed in.

The value of tmp_ptr->current_longitude is 6722.31500000, and the value of tmp_ptr->current_latitude is 930.0876500000.

After using the sprintf statements:

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

I expect the exact same results for speed_info->myXPos and speed_info->myYPos but strangely even though speed_info->myXPos = 6722.31500000 and the value of speed_info->myYPos > = 30.0876500000, the sprintf statements

charSpeedPtrYPos= "930.0877"

So basically the sprintf statement behaves differently for the second value and appears to round it up. Having debugged this I know the input to the sprintf statement is exactly the same.

Can anyone think of a reason for this?

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

Upvotes: 1

Views: 1931

Answers (3)

chux
chux

Reputation: 153457

It is the difference between a float and a double.

OP is likely using tmp_ptr->current_latitude as a float and speed_info->myYPos as a double. Suggest OP use double though-out unless space/speed oblige the use of 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

As the typical float uses a IEEE 4-byte binary floating point representation, f1 takes on the exact value of
930.087646484375
930.0876 (This is the 4 digit printed result)
This is the closest float value to 930.08765.

Like-wise, for a double, d1 takes on the exact value of
930.0876500000000532963895238935947418212890625
930.0877 (This is the 4 digit printed result)

In general, one could use more decimal places to reduce the likely-hood of this happening with other numbers, but not eliminate it.


Candidate quick fix

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

This would first convert the value from speed_info->myYPos to a float. As non-prototyped parameters of type float are converted to double before being passed to sprintf(), the value would get converted back to double. The net result is a loss of precision in the number, but the same string conversion results.

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

BTW: The l in "%0.4lf" serves no code generation purpose. It is allowed though.

Upvotes: 2

Pascal Cuoq
Pascal Cuoq

Reputation: 80276

printf() typically rounds to the nearest decimal representation, with ties sent to the “even” one (that is, the representation whose last digit is 0, 2, 4, 6, or 8).

However, you must understand that most numbers that are finitely representable in decimal are not finitely representable in binary floating-point. The real number 930.08765, for instance, is not representable as binary floating-point. What you really have as a double value (and what is converted to decimal) is another number, likely slightly above 930.08765, in all likelihood 930.0876500000000532963895238935947418212890625. It is normal for this number to be rounded to the decimal representation 930.0877 since it is closer to this representation than to 930.0876.


Note that if you are using Visual Studio, your *printf() functions may be limited to showing 17 significant digits, preventing you from observing the exact value of the double nearest 930.08765.

Upvotes: 4

andreas
andreas

Reputation: 985

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

A dot followed by a number specifies the precision, which is 4 in your case. Try to use a higher presicion if you need it. I have tried your number with a precision of 5 and it isn't rounded up anymore. So it should be..

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

..or any higher number which fits your needs.

Upvotes: 0

Related Questions