Одинарное и двойное литье дает разные ответы - PullRequest
1 голос
/ 02 ноября 2011

Итак, у меня есть следующий код:

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

Это дает 12, как и должно быть, учитывая 20 * 0,6 = 12. Однако, если я изменю все числа с плавающей запятой на удваиваемые:

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

Это дает мне 11 вместо этого.И что еще более странно, если я изменю код так, чтобы значение сохранялось сначала в переменной, а затем в регистре после, это снова дает правильный ответ (12).

#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();
}

Что во имя Богаздесь происходит?Я использую g ++ 4.5.3 для компиляции.

1 Ответ

8 голосов
/ 02 ноября 2011

0.6 не может быть точно представлен ни в одном двоичном формате с плавающей запятой.Иногда это несколько больше и несколько меньше, в зависимости от типа данных.См. Что должен знать каждый программист об арифметике с плавающей запятой для подробного объяснения.

Версия 'store in memory' отличается, потому что FPU x87 использует 80-битные регистры с плавающей запятой внутри.

РЕДАКТИРОВАТЬ: Подробный расчет:

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
...