(int)(33.46639 * 1000000) возвращает 33466389
Почему это происходит?
(int)(33.46639 * 1000000) возвращает 33466389
Почему это происходит?
Математика с плавающей точкой не идеальна. Что каждый программист должен знать об этом.
Арифметика с плавающей точкой рассматривается многими эзотерическими субъектами. Это довольно удивительно, потому что плавающая точка вездесуща в компьютерных системах. Почти каждый язык имеет тип данных с плавающей запятой; компьютеры от ПК до суперкомпьютеров имеют ускорители с плавающей запятой; большинство компиляторов будут вынуждены время от времени компилировать алгоритмы с плавающей запятой; и практически каждая операционная система должна реагировать на исключения с плавающей запятой, такие как переполнение. В этом документе представлен учебник по тем аспектам с плавающей точкой, которые оказывают непосредственное влияние на разработчиков компьютерных систем. Он начинается с фона по представлению с плавающей запятой и ошибки округления, продолжается с обсуждением стандарта с плавающей запятой IEEE и заканчивается многочисленными примерами того, как сборщики компьютеров могут лучше поддерживать плавающие точки.
...
Сжатие бесконечного числа действительных чисел в конечное число бит требует приблизительного представления. Несмотря на то, что в большинстве программ имеется бесконечно много целых чисел, результат целочисленных вычислений может быть сохранен в 32 битах. В отличие от этого, учитывая любое фиксированное количество бит, большинство вычислений с реальными числами будут давать количества, которые не могут быть точно представлены с использованием этого количества бит. Поэтому результат вычисления с плавающей запятой часто должен быть округлен, чтобы соответствовать его конечному представлению. Эта ошибка округления является характерной особенностью вычисления с плавающей запятой.
Двойная точность не является точной, поэтому внутренне 33.46639 фактически хранится как 33.466389
Изменить: как сказал Ричард, данные с плавающей запятой (хранятся в двоичном виде в конечном наборе бит), так что это не совсем так)....
Это был канун Нового года в конце 1994 года. Энди Гроув, генеральный директор Intel, близок к тому, что процессор Pentium выходит и становится большим хитом. Итак, он вошел в бар и заказал двойной снимок "Яркий ярлык" Джонни Уокера.
Бармен обслужил его и сказал: "Это будет 20 долларов США, сэр".
Гроув поставил счетчик на двадцать долларов на счетчик, посмотрел на него на мгновение и сказал: "Сохраните изменения".Причина в том, что 33.46639 будет представлен как нечто немного меньшее, чем это число.
Умножение на 1000000 даст вам 33466389.99999999.
Тип-литье с использованием (int) просто вернет целочисленную часть (33466389).
Если вы хотите "правильное" число, попробуйте round() перед тем, как накладывать тип.
Если вы спрашиваете, почему он не стал 33466390, это потому, что double не имеет бесконечной точности, и число не может быть точно выражено в двоичном формате.
Если вы замените double на decimal ((int)(33.46639m * 1000000)), он будет равен 33466390, потому что decimal вычисляются в базе 10.
Потому что 33.46639 не может быть точно выражен в конечном числе двоичных цифр. Фактический результат 33.46639 * 1000000 - 33466389.9999999962747097015380859375. Литье усекает его до 33466389.
Причина, по которой вы получили другой результат, - это то, что вы использовали "cast"
(int)(33.46639 * 1000000) returns 33466389 ^^^^^
чтобы привести результат к типу 'int'... который либо округлялся вверх или вниз по интегральному типу при умножении вместе, а затем преобразовывался в 'int'.... не полагайтесь на плавающую точку, чтобы быть достаточно точным.... Skeet опубликовал отличное введение на своем сайте здесь и здесь...