Почему (int)(33.46639 * 1000000) возвращает 33466389?
-
19-09-2019 - |
Вопрос
(int)(33.46639 * 1000000)
ВОЗВРАТ 33466389
Почему это происходит?
Решение
Математика с плавающей запятой не идеальна. Что должен знать каждый программист об этом.
Многие люди считают арифметику с плавающей запятой эзотерическим предметом.Это довольно удивительно, потому что формат с плавающей запятой широко распространен в компьютерных системах.Почти каждый язык имеет тип данных с плавающей запятой;компьютеры, от персональных компьютеров до суперкомпьютеров, имеют ускорители с плавающей запятой;большинству компиляторов время от времени приходится компилировать алгоритмы с плавающей запятой;и практически каждая операционная система должна реагировать на исключения с плавающей запятой, такие как переполнение.В этой статье представлено руководство по тем аспектам операций с плавающей запятой, которые оказывают непосредственное влияние на разработчиков компьютерных систем.Она начинается с предыстории представления с плавающей запятой и ошибки округления, продолжается обсуждением стандарта IEEE с плавающей запятой и заканчивается многочисленными примерами того, как разработчики компьютеров могут лучше поддерживать формат с плавающей запятой.
...
Сжатие бесконечно большого числа вещественных чисел в конечное число битов требует приблизительного представления.Хотя целых чисел существует бесконечно много, в большинстве программ результат целочисленных вычислений может храниться в 32 битах.Напротив, при любом фиксированном количестве битов большинство вычислений с действительными числами приведут к величинам, которые не могут быть точно представлены с использованием такого количества битов.Поэтому результат вычисления с плавающей запятой часто приходится округлять, чтобы снова вписаться в его конечное представление.Эта ошибка округления является характерной чертой вычислений с плавающей запятой.
Другие советы
Двойная точность не является точной, поэтому внутренне 33.46639 фактически хранится как 33.466389
Редактировать:Как сказал Ричард, это данные с плавающей запятой (хранятся в двоичном формате с конечным набором битов), так что это не совсем так) ....
Это был канун Нового года в конце 1994 года.Энди Гроув, генеральный директор Intel, заканчивал отличный год, выпустив процессор Pentium, который стал большим хитом.Итак, он зашел в бар и заказал двойную порцию Johnnie Walker Green Label.
Бармен подал его и сказал: "С вас 20 долларов, сэр".
Гроув положил на стойку двадцатидолларовую купюру, мгновение смотрел на нее и сказал: "Сдачу оставьте себе".
Причина в том, что 33.46639 будет представлено как нечто немного меньшее, чем это число.
Умножение на 1000000 даст вам 33466389,99999999.
Приведение типов с использованием (int) затем просто вернет целую часть (33466389).
Если вам нужно "правильное" число, попробуйте round() перед приведением типа.
Если вы спрашиваете, почему это не становится 33466390
, это потому , что double
s не обладают бесконечной точностью, и число не может быть точно выражено в двоичном формате.
Если вы замените double
с помощью decimal
((int)(33.46639m * 1000000)
), оно будет равно 33466390
, потому что decimal
s рассчитываются по базе 10.
Потому что 33.46639 не может быть точно выражено конечным числом двоичных цифр.Фактический результат 33.46639 * 1000000 равен 33466389.99999999662747097015380859375.Приведение сокращает его до 33466389.
Причина, по которой вы получили другой результат, заключается в том, что вы использовали 'бросок'
(int)(33.46639 * 1000000) returns 33466389 ^^^^^
чтобы привести результат к типу 'int'...который либо округляет в большую, либо в меньшую сторону тип integral при умножении вместе, а затем преобразует в 'int'....не полагайтесь на плавающую точку, чтобы быть достаточно точным....Скит опубликовал отличное введение на своем сайте здесь и здесь...