Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why storing a double expression in a variable before a cast to int can lead to different results than casting it directly?

I write this short program to test the conversion from double to int:

int main() {
    int a;
    int d; 
    double b = 0.41;

    /* Cast from variable. */
    double c = b * 100.0;
    a = (int)(c);

    /* Cast expression directly. */
    d = (int)(b * 100.0);

    printf("c = %f \n", c);
    printf("a = %d \n", a);
    printf("d = %d \n", d);

    return 0;
}

Output:

c = 41.000000 
a = 41 
d = 40 

Why do a and d have different values even though they are both the product of b and 100?

like image 765
Jay Dao Avatar asked Jun 20 '13 18:06

Jay Dao


People also ask

Can we convert int to double in C?

The %d format specifier expects an int argument, but you're passing a double . Using the wrong format specifier invokes undefined behavior. To print a double , use %f .

Can we assign a float variable to a long integer variable?

You can safely assign a floating point variable to an integer variable, the compiler will just truncate (not round) the value. At most the compiler might give you a warning, especially if assigning from e.g. a double or bigger type.


1 Answers

The C standard allows a C implementation to compute floating-point operations with more precision than the nominal type. For example, the Intel 80-bit floating-point format may be used when the type in the source code is double, for the IEEE-754 64-bit format. In this case, the behavior can be completely explained by assuming the C implementation uses long double (80 bit) whenever it can and converts to double when the C standard requires it.

I conjecture what happens in this case is:

  • In double b = 0.41;, 0.41 is converted to double and stored in b. The conversion results in a value slightly less than .41.
  • In double c = b * 100.0000;, b * 100.0000 is evaluated in long double. This produces a value slightly less than 41.
  • That expression is used to initialize c. The C standard requires that it be converted to double at this point. Because the value is so close to 41, the conversion produces exactly 41. So c is 41.
  • a = (int)(c); produces 41, as normal.
  • In d = (int)(b * 100.000);, we have the same multiplication as before. The value is the same as before, something slightly less than 41. However, this value is not assigned to or used to intialize a double, so no conversion to double occurs. Instead, it is converted to int. Since the value is slightly less than 41, the conversion produces 40.
like image 87
Eric Postpischil Avatar answered Oct 26 '22 15:10

Eric Postpischil