Pull to refresh

Comments 42

В Java — лучше использовать только BigDecimal для точных расчетов!

Десятичное число 0.1 невозможно представить в двоичной системе с плавающей запятой конечной точности -> двоичное представление будет иметь последовательность «1100», продолжающуюся бесконечно — е = -4; s = 110011001100110011001101 и так далее…
При округлении до 24 бит получится 0,100000001490116119384765625 в десятичном виде

У меня это в голове не укладывается с урока информатики, где учили переводить десятичные в двоичные.
Почему нельзя хранить отдельно значение (ну там до 10 знака, мы же не число пи пытаемся сохранить) и отдельно "расстояние до точки". В данном случае получаем число 1 ровно и степень десятки -1. И все расчёты так и вести параллельно. Перемножаем/складываем/делим целые числы, получаем новые целые числа (возможно с доп. смещением) и потом обрабатываем степени десяток этих чисел (и доп. смещение, если появилось). И на выходе опять получаем нормальное целое число и его степень десятки без всяких этих ваших хвостов.
То есть как в школе в тетрадке в столбик.

Ну так и есть мантисса, и порядок.
Речь в компромиссе между точностью и диапазоном значений.

во-первых, так сложилось исторически
во-вторых, так проще обрабатывать числа с плавающей запятой (на сопроцесорах, или в рамках интсрукций процессора)
есть и другие форматы, например числа с фиксированной точностью. Или, пару лет назад на хабре писали статью про запись дробных чисел именнно в виде дробей
UFO just landed and posted this here

Я думаю имеется ввиду почему мантисса — дробное число, а не как обычный integer (целое число).


Насколько я понял, хранится в виде дробной части потому что 3 бита это 8, а 4 бита это уже 16. И как это отразить на десятиричную систему счисления не очень понятно, поэтому и оказалось что проще и логичнее двигаться дальше по степеням в обратную сторону (т.е. каждый новый бит — результат чётности деления предыдущего остатка на два).

Если бы мантисса была целым числом, то существовала бы возможность представить одно и то же число разными способами.
1 = 10е-1 = 100е-2 (это на десятичном примере).
Чтобы этого избежать, принято, что мантисса всегда (0.1; 1)

UFO just landed and posted this here
ну серьезно?
вам за написание статей платят чтоли?
что завтра? статьтя«я нажал кнопочку на компютере и он заработал ЫЫЫть 11111!!!!»

Следующая статья — "Как получилось, что сеньор-программеры на JavaScript не знают о существовании чисел с плавающей точкой, но им это совершенно не мешает?".
(глядишь, скоро будет "256 не влезает в байт. Я фшоке.")

так пишущие на javascript не в курсе про байты же. У них все числа исключительно float.
Ну, по-хорошему, эта тема важная — я когда первый раз накосячил с точным расчетом в double — таких люлей получил)
Тема очень правильная. Числа с плавающей точкой применяются налево и направо. Сейчас даже производительности микроконтроллеров хватает, чтобы их спокойно использовать. При этом очень часто вот о таких казусах, как описано в данной статье, забывают, что может приводить к различным неприятностям.
>Тема очень правильная.
И поэтому надо практически идентичные статьи штамповать раз в месяц примерно? 26 декабря предпоследняя была. Ищется поиском по 0,30000000000000004, можете сами проверить.
А в чём проблема-то? На Хабре место кончится? ;-) Я, например, ту статью не видел, эту прочитал. Таким образом охват аудитории больше получается. Те, кто уже читал подобное, могут просто спокойно мимо пройти.
Проблема в том, что эта статья — мусор, так же как впрочем и предыдущая. Почему мусор? Да вот поэтому, например:

>Проведя много исследований и вычислений, я пришел к выводу, что это не ошибка. Это математика: арифметика с плавающей запятой.

Нет, это не арифметика с плавающей запятой. Это может быть например и преобразование из десятичного представления в двоичное — и вообще никакой плавающей запятой не будет, а проблема будет. Просто дробь 1/3 в двоичной системе является периодической. А плавающая точка возникает уже потом, потому что представить бесконечную периодическую дробь в виде числа с фиксированным числом знаком компьютер не умеет.

Проблема чуть сложнее, и чтобы ее решить — лучше почитать учебник, а не статью, написанную кем-то, кто:

>Я обратился за помощью к Stack Overflow и нашел пару сообщений
Но ведь для того, чтобы начать читать учебник вначале надо осознать проблему. Я уверен, что некоторые над ней даже не задумывались.
Ну, как-то для осознания проблемы все-таки две статьи в месяц многовато :)

Поймите правильно — я не против темы. Она реально норм, кто бы сомневался. Я против того, чтобы перед публикацией не поискать хотя бы, а не было ли уже такого же тут. И в данном случае — я не верю, что автор это пытался проделать.
Вы считаете, что хабр — только для тех, «кому за 20 (30, 40)»?
Я смотрю сейчас на очень начинающего человека, который ещё в школе учится, и ему эта информация полезна.
Здесь реально мало статей с низким «порогом вхождения».
Я это, допустим, и сам ребёнку могу объяснить, когда он доберётся до факта, но проще, если он прочтёт самостоятельно. Да и к ресурсу привыкает.
К хорошему, без матов и разной дичи.

Очень начинающий (я помню, как я начинал), будет искать не на Хабре, а в Гугле (или ином поисковике). Нужная ему статья найдётся может на Хабре, а может нет.
Привыкать к ресурсу, на который заходишь от случая к случаю через поисковик… Ну не знаю...

Помнится, про такие фокусы нам как раз рассказали в школе в 10 классе на уроке информатики.

Ну и продолжите статью выводом как правильно сравнивать числа с плавающей точкой в JavaScript, а то какая-то неоконченная получается.

многочисленные объяснения «почему так получилось» и ни одного «как сделать что бы такого не было».

более того, на втором скриншоте с питоном 2.7 явно другая причина, потому что там результат отличный от 0,30000000000000004.
Уууу! Какие древние темы всплывают. Еще когда учился (1984), учитель говорил: «дети, не используйте тип float для прямых сравнений. А если сильно хочется, то используйте конструкции типа „fabs(a-b)<“точность сравнения»"
if (fabs(a-b) <0.0001)
  {величины равны с точностью до ...}
else
  {а и b сидели на трубе}

а если точнее то
c=a-b
if ((c>-0.0001) && (с <0.0001))
  {величины равны с точностью до ...}
else
  {а и b сидели на трубе}
А какая разница между двумя примерами?

Да собственно никакой. Отрицательные числа от положительных отличаются битом знака. Мантисса и порядок одинаковые, точность не страдает.

Надо начинать считать статьи на хабре на эту тему.

Причем в динамике: есть у меня подозрение, что с каждым годом таких статей становится все больше, а статей уровня «пропатчить KDE под FreeBSD» все меньше.
Когда-то в инструкциях к автомобилю писали, как отрегулировать зазоры клапанов в двигателе, а сейчас пишут о том, что нельзя пить охлаждающую жидкость)
UFO just landed and posted this here

Читать надо внимательнее. У того бага принципиально другая причина.

Особенно комментарии — там эту байку почти сразу аргументированно разнесли
> (= 1/10 0.1)
> NIL

Так что нещитается

Я тоже когда-то испытал недоумение, когда впервые наткнулся на это. Имхо считаю, что нет ничего плохого в написании статьи, у которой уже есть подобная тема, вот только нужно не копировать или менять пару слов (не конкретно к этой статье, а в целом) и приподнести что-то новое. Например, как эти проблему решают сейчас (ведь возможно в старых статьях это решается по-другому), как с этим борется сам язык или его комьюнити.


Кстати, еще один кейс для Java:


double a = 2.5 + 5/10;   // = 2.5

Думаю, все это относится к мелочам, которые довольно важно знать (в том числе и переполнения)

Кстати, еще один кейс для Java:
А в чём кейс? Разделили одно целое (int) число на другое — получили 0, т.к. 0.5 целым никак не получится сделать. Следовательно 2.5 + 0 -> 2.5
И никаких подвохов
для меня статья была позновательной. Я регулярно наблюдаю странные цифры вместо нормальных внутри одной программы. Т.е. отображается нормальная цифра, а в режиме редактирования такая вот шляпа. Но правда я не понял как можно победить эту шляпу
Sign up to leave a comment.

Articles