parent5446
parent5446

Reputation: 898

Single-Precision and Double-Precision Casting Gives Different Answers

So I have the following code:

#include <iostream>
int main(){
    float number = 0.6;
    int anotherNumber = 20;
    int value = (int) ((float) anotherNumber * number);
    std::cout << value;
    std::cin.get();
}

It gives 12, like it should considering 20 * 0.6 = 12. However, if I change all floats to doubles:

#include <iostream>
int main(){
    double number = 0.6;
    int anotherNumber = 20;
    int value = (int) ((double) anotherNumber * number);
    std::cout << value;
    std::cin.get();
}

It gives me 11 instead. And to make things even weirder, if I change the code so that the value is stored in a variable first and then case after, it gives the right answer (12) again.

#include <iostream>
int main(){
    double number = 0.6;
    int anotherNumber = 20;
    double intermediate = (double) anotherNumber * number;
    int value = (int) intermediate;
    std::cout << value;
    std::cin.get();
}

What in God's name is going on here? I'm using g++ 4.5.3 to compile.

Upvotes: 1

Views: 5099

Answers (1)

Yakov Galka
Yakov Galka

Reputation: 72539

0.6 cannot be represented in any binary floating point format exactly. Sometimes it somewhat larger and somewhat it's somewhat smaller, depending on the data-type. See What Every Programmer Should Know About Floating-Point Arithmetic for detailed explanation.

The 'store in memory' version is different because the x87 FPU uses 80-bit floating point registers internally.

EDIT: Detailed computation:

float 0.6 in memory;
.100110011001100110011010
loaded to register:
.10011001100110011001101000000000000000000000000000000000000000000
multiplied by 20:
1100.0000000000000000000010000000000000000000000000000000000000000
rounded down:
1100

double 0.6 in memory
.10011001100110011001100110011001100110011001100110011
loaded to register:
.10011001100110011001100110011001100110011001100110011000000000000
multiplied by 20:
1011.1111111111111111111111111111111111111111111111111110000000000
rounded down:
1011

double 0.6 in memory
.10011001100110011001100110011001100110011001100110011
loaded to register:
.10011001100110011001100110011001100110011001100110011000000000000
multiplied by 20:
1011.1111111111111111111111111111111111111111111111111110000000000
converted to double-precision and stored to memory:
1100.0000000000000000000000000000000000000000000000000
loaded to register:
1100.0000000000000000000000000000000000000000000000000000000000000
rounded down:
1100

Upvotes: 8

Related Questions