简体   繁体   中英

strange double to int conversion behavior in c++

The following program shows the weird double to int conversion behavior I'm seeing in c++:

#include <stdlib.h>
#include <stdio.h>

int main() {
  double d = 33222.221;
  printf("d = %9.9g\n",d);

  d *= 1000;
  int i = (int)d;

  printf("d = %9.9g | i = %d\n",d,i);

  return 0;
}

When I compile and run the program, I see:

g++ test.cpp
./a.out
d = 33222.221
d =  33222221 | i = 33222220

Why is i not equal to 33222221? The compiler version is GCC 4.3.0

Floating point representation is almost never precise (only in special cases). Every programmer should read this: What Every Computer Scientist Should Know About Floating-Point Arithmetic

In short - your number is probably 33222220.99999999999999999999999999999999999999999999999999999999999999998 (or something like that), which becomes 33222220 after truncation.

When you attach a debugger and inspect the values, you will see that the value of d is actually 33222220.999999996 , which is correctly truncated to 33222220 when converted to integer.

There is a finite amount of numbers that can be stored in a double variable, and 33222221 is not one of them.

Due to floating point approximation, 33222.221 may actually be 33222.220999999999999. Multiplied by 1000 yields 33222220.999999999999. Casting to integer ignores all decimals (round down) for a final result of 33222220.

If you change the "9.9g" in your printf() calls to 17.17 to recover all possible digits of precision with a 64-bit IEEE 754 FP number, you get 33222220.999999996 for the double value. The int conversion then makes sense.

I don't want to repeat the explanations of the other comments.

So, here is just an advice to avoid problems like the one described:

  1. Avoid floating point arithemtics in the first place whereever possible (especially when computation is involved).

  2. If floating point arithmetics is really necessary, you must not compare numbers by operator== by all means! Use your own comparison function instead (or use one supplied by some library), which does something like an "is almost equal" comparison using some kind of epsilon compare (either absolute or relative to the number's magniture).

See for example the excellent article

http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm

by Bruce Dawson instead!

Stefan

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM