Reputation: 21
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
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
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
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