Comments 42
Десятичное число 0.1 невозможно представить в двоичной системе с плавающей запятой конечной точности -> двоичное представление будет иметь последовательность «1100», продолжающуюся бесконечно — е = -4; s = 110011001100110011001101 и так далее…
При округлении до 24 бит получится 0,100000001490116119384765625 в десятичном виде
У меня это в голове не укладывается с урока информатики, где учили переводить десятичные в двоичные.
Почему нельзя хранить отдельно значение (ну там до 10 знака, мы же не число пи пытаемся сохранить) и отдельно "расстояние до точки". В данном случае получаем число 1 ровно и степень десятки -1. И все расчёты так и вести параллельно. Перемножаем/складываем/делим целые числы, получаем новые целые числа (возможно с доп. смещением) и потом обрабатываем степени десяток этих чисел (и доп. смещение, если появилось). И на выходе опять получаем нормальное целое число и его степень десятки без всяких этих ваших хвостов.
То есть как в школе в тетрадке в столбик.
Ну так и есть мантисса, и порядок.
Речь в компромиссе между точностью и диапазоном значений.
во-вторых, так проще обрабатывать числа с плавающей запятой (на сопроцесорах, или в рамках интсрукций процессора)
есть и другие форматы, например числа с фиксированной точностью. Или, пару лет назад на хабре писали статью про запись дробных чисел именнно в виде дробей
Я думаю имеется ввиду почему мантисса — дробное число, а не как обычный integer (целое число).
Насколько я понял, хранится в виде дробной части потому что 3 бита это 8, а 4 бита это уже 16. И как это отразить на десятиричную систему счисления не очень понятно, поэтому и оказалось что проще и логичнее двигаться дальше по степеням в обратную сторону (т.е. каждый новый бит — результат чётности деления предыдущего остатка на два).
вам за написание статей платят чтоли?
что завтра? статьтя«я нажал кнопочку на компютере и он заработал ЫЫЫть 11111!!!!»
Следующая статья — "Как получилось, что сеньор-программеры на JavaScript не знают о существовании чисел с плавающей точкой, но им это совершенно не мешает?".
(глядишь, скоро будет "256 не влезает в байт. Я фшоке.")
И поэтому надо практически идентичные статьи штамповать раз в месяц примерно? 26 декабря предпоследняя была. Ищется поиском по 0,30000000000000004, можете сами проверить.
>Проведя много исследований и вычислений, я пришел к выводу, что это не ошибка. Это математика: арифметика с плавающей запятой.
Нет, это не арифметика с плавающей запятой. Это может быть например и преобразование из десятичного представления в двоичное — и вообще никакой плавающей запятой не будет, а проблема будет. Просто дробь 1/3 в двоичной системе является периодической. А плавающая точка возникает уже потом, потому что представить бесконечную периодическую дробь в виде числа с фиксированным числом знаком компьютер не умеет.
Проблема чуть сложнее, и чтобы ее решить — лучше почитать учебник, а не статью, написанную кем-то, кто:
>Я обратился за помощью к Stack Overflow и нашел пару сообщений
Поймите правильно — я не против темы. Она реально норм, кто бы сомневался. Я против того, чтобы перед публикацией не поискать хотя бы, а не было ли уже такого же тут. И в данном случае — я не верю, что автор это пытался проделать.
Я смотрю сейчас на очень начинающего человека, который ещё в школе учится, и ему эта информация полезна.
Здесь реально мало статей с низким «порогом вхождения».
Я это, допустим, и сам ребёнку могу объяснить, когда он доберётся до факта, но проще, если он прочтёт самостоятельно. Да и к ресурсу привыкает.
К хорошему, без матов и разной дичи.
Очень начинающий (я помню, как я начинал), будет искать не на Хабре, а в Гугле (или ином поисковике). Нужная ему статья найдётся может на Хабре, а может нет.
Привыкать к ресурсу, на который заходишь от случая к случаю через поисковик… Ну не знаю...
Ну и продолжите статью выводом как правильно сравнивать числа с плавающей точкой в JavaScript, а то какая-то неоконченная получается.
более того, на втором скриншоте с питоном 2.7 явно другая причина, потому что там результат отличный от 0,30000000000000004.
if (fabs(a-b) <0.0001)
{величины равны с точностью до ...}
else
{а и b сидели на трубе}
а если точнее то
c=a-b
if ((c>-0.0001) && (с <0.0001))
{величины равны с точностью до ...}
else
{а и b сидели на трубе}
Использовать модуль разности для сравнения чисел с плавающей точкой тоже не совсем корректно.
Причем в динамике: есть у меня подозрение, что с каждым годом таких статей становится все больше, а статей уровня «пропатчить KDE под FreeBSD» все меньше.
Как один маленький баг угробил 28 американцев
> (+ 1/10 2/10)
> 3/10
:-P
Я тоже когда-то испытал недоумение, когда впервые наткнулся на это. Имхо считаю, что нет ничего плохого в написании статьи, у которой уже есть подобная тема, вот только нужно не копировать или менять пару слов (не конкретно к этой статье, а в целом) и приподнести что-то новое. Например, как эти проблему решают сейчас (ведь возможно в старых статьях это решается по-другому), как с этим борется сам язык или его комьюнити.
Кстати, еще один кейс для Java:
double a = 2.5 + 5/10; // = 2.5
Думаю, все это относится к мелочам, которые довольно важно знать (в том числе и переполнения)
Как получилось, что 0,1 + 0,2 = 0,30000000000000004?