Почему (int) (33.46639 * 1000000) возвращает 33466389? - PullRequest
18 голосов
/ 11 марта 2010

(int)(33.46639 * 1000000) возвращает 33466389

Почему это происходит?

Ответы [ 7 ]

31 голосов
/ 11 марта 2010

Математика с плавающей точкой не идеальна. Что должен знать каждый программист .

Арифметика с плавающей точкой многими считается эзотерическим предметом. Это довольно удивительно, потому что с плавающей точкой в ​​компьютерных системах повсеместно. Почти у каждого языка есть тип данных с плавающей точкой; компьютеры от ПК до суперкомпьютеров имеют ускорители с плавающей запятой; большинство компиляторов будут время от времени компилировать алгоритмы с плавающей точкой; и практически каждая операционная система должна реагировать на исключения с плавающей точкой, такие как переполнение. Эта статья представляет учебное пособие по тем аспектам с плавающей точкой, которые имеют непосредственное влияние на разработчиков компьютерных систем. Он начинается с предыстории представления с плавающей точкой и ошибки округления, продолжается обсуждением стандарта IEEE с плавающей точкой и заканчивается многочисленными примерами того, как компиляторы компьютеров могут лучше поддерживать с плавающей точкой.

...

Сжатие бесконечного числа действительных чисел в конечное число бит требует приблизительного представления. Хотя целых чисел бесконечно много, в большинстве программ результат целочисленных вычислений может храниться в 32 битах. Напротив, при любом фиксированном количестве битов большинство вычислений с действительными числами будут давать величины, которые не могут быть точно представлены с использованием такого количества битов. Поэтому результат вычисления с плавающей точкой часто должен быть округлен, чтобы соответствовать его конечному представлению. Эта ошибка округления является характерной особенностью вычисления с плавающей точкой.

5 голосов
/ 11 марта 2010

Двойная точность не является точной, поэтому внутренне 33.46639 фактически сохраняется как 33.466389

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

3 голосов
/ 11 марта 2010

В конце 1994 года наступил канун Нового года. Энди Гроув, генеральный директор Intel, начал замечательный год, когда появился процессор Pentium, получивший большой успех. Итак, он вошел в бар и заказал двойной выстрел Джонни Уокера Грин Лейбл.

Бармен подал его и сказал: «Это будет 20 долларов, сэр».

Гроув положил на прилавок двадцатидолларовую купюру, посмотрел на нее и сказал: «Оставь сдачу»

http://en.wikipedia.org/wiki/Pentium_FDIV_bug

2 голосов
/ 11 марта 2010

Причина в том, что 33.46639 будет представлено как нечто немного меньшее, чем это число.

Умножение на 1000000 даст вам 33466389.99999999.

Приведение типов с использованием (int) просто возвращает целочисленную часть (33466389).

Если вам нужно «правильное» число, попробуйте round () перед приведением типа.

1 голос
/ 11 марта 2010

Потому что 33.46639 не может быть выражено точно в конечном количестве двоичных цифр. Фактический результат 33,46639 * 1000000 составляет 33466389,9999999962747097015380859375. Приведение усекает его до 33466389.

1 голос
/ 11 марта 2010

Если вы спрашиваете, почему оно не становится 33466390, это потому, что double не имеют бесконечной точности, и число не может быть выражено точно в двоичном виде.

Если вы замените double на decimal ((int)(33.46639m * 1000000)), он будет равен 33466390, потому что decimal s вычисляются в базе 10.

0 голосов
/ 11 марта 2010

Причина, по которой вы получили другой результат, заключается в том, что вы использовали ' cast '

(int)(33.46639 * 1000000) returns 33466389
^^^^^

для приведения результата к типу 'int' ... который либо округляется в большую или меньшую сторону целочисленного типа, когда умножается вместе, а затем преобразуется в 'int' .... не полагайтесь на точность с плавающей точкой .... Скит разместил отличное введение на своем сайте здесь и здесь ...

...