Pull to refresh

Comments 19

по той же причине это на самом деле не баг.

Это не баг, просто javascript — язык для небольших скриптов на веб-страницах, когда он разрабатывался — никто и представить не мог, что кто-то будет писать на этом программы. Но мир сошёл с ума и теперь его пихают везде. Ещё бы из bat-файлов программы писали.
json = JSON.parse(‘{“x”: 2940078943461317278}’); alert(json[‘x’]);

Это очень небольшой скрипт для вебстраницы. Практически даже минимальный.

Скромность масштаба программы и магнитуды используемых в ней чисел — две большие разницы, как говорят в одном славном приморском городе.
И зачем такой скрипт нужен сам по себе? Большие числа редко нужны для примитивных действий в программе. А когда разрабатывался javascript ни о каких аяксах и прочих обменов с сервером в формате json никто не думал. Да и сам формат как отдельное явление появился много позже.
Ну, например, огромная доля идентификаторов, выполняющих роль primary key в базах данных, являются 64битными целыми. Более того, обычно именно такой тип данных — решение по дефолту для первичного ключа. Если даже просто отображать данные из такой базы «самым примитивным действием» — легко влететь, забыв, что в JS только double, емкость мантиссы которого только 53 бита.

Другой пример, — значения хешей для технических надобностей неглобального характера (всякие GUID-подобные идентификаторы, например) часто приводят к int64. Опять же потребуется их «примитивно» вывести с помощью JS — очень не всякий подумает, что с ними придётся работать как со строками…

Другими словами — вариантов, где возникнут большие «числа» на самом деле предостаточно даже в очень простых и примитивных вариантах использования. А сравнивать современный JS с тем, что было изначально выпущено… Какой смысл? Язык эволюционирует.
… просто javascript — язык для небольших скриптов на веб-страницах, когда он разрабатывался — никто и представить не мог, что кто-то будет писать на этом программы. Но мир сошёл с ума и теперь его пихают везде. Ещё бы из bat-файлов программы писали.

Не очень понятно как это соотносится со сказанным в статье. Так-то в JS для представления чисел используется float64, диапазон целых в котором сильно больше (примерно в 4 миллиона раз), чем скажем в int32, который для представления целых чисел использовался десятилетиями. Ошибку в алгоритме вычисления среднего арифметического так и вовсе только через 20 с лишним лет нашли.
UFO just landed and posted this here
UFO just landed and posted this here
UFO just landed and posted this here
UFO just landed and posted this here
Наверно, это здорово, когда язык позволяет программисту абстрагироваться от машинного представления действительных чисел и ожидать, что
… должно возвращаться целочисленное значение 2940078943461317278.
Если работаешь с небольшими числами, а все вычисления идут в real*8, то можно за всю жизнь ни разу не столкнуться с подобными багами. А вот программист на фортране или на Си, наоборот, удивится: «с чего это вдруг 29400… 278»? Ведь в классических языках минимальный real — 4-байтовый, а с ним такие штуки начинаются уже в 7-8 десятичном знаке. Для примера, если число равно XXX, то шаг между соседними представимыми real*4 -числами равен YYY:

   XXX		        YYY
16 800 000	 	2
 1 680 000		0.2 
   168 000		0.02
    16 800 		0.002
     1 680 		0.0002
       168 		0.000 02
        16.8 		0.000 0002
         1.68 		0.000 000 02
         0.168 		0.000 000 002


Благодаря стандарту IEEE S_floating так было 30 лет назад (когда я только осваивал фортран-4 на 286 процессоре), и точно так же сейчас. Человеку, который пишет тип переменной в явном виде (независимо от разрядности), и в голову не придет ожидать, что вычисления с плавающей точкой могут быть «точными», так как понятия (функции) EPSILON(X), NEAREST(X, S) и другие подобные у него изначально прошиты в мозгу. Даже не знаю, хорошо это или плохо…

Если что, вот тут можно чуть подробнее посмотреть про машинное представление real*4 и real*8: «www.softelectro.ru/ieee754.html».
Правда, довольно странно, что поиск в интернете все время выводит только на 32- и 64-битные стандарты IEEE S_floating и IEEE T_floating. Компилятор Intel Fortran уже в 2013г наравне с ними позволял использовать 128-битный формат IEEE X_floating. (В фортране это сейчас пишется, как REAL(16), или REAL(KIND=16)). На мантиссу в этом случае отводится 113 бит, соответственно экспонента может быть от -16381 до 16384. Как написано в справке, «Extended-precision real floating-point values in IEEE-style X_floating format ranging from 6.4751751194380251109244389582276465524996Q-4966 to 1.189731495357231765085759326628007016196477Q4932».

Вангую, что лет через 30, когда этот стандарт станет дефолтным, а языки, позволяющие (требующие?) явно указывать разрядность числа, уйдут глубоко в андерграунд, столкновение с описанными в статье багами (на новом уровне точности) будет вызывать настоящий шок, так как в мэйнстриме практически не останется специалистов, способных в них разобраться, объяснить и поправить…
Я сталкивался этим явлением в очень интересном месте — в .net библиотеке для работы с elasticsearch.
У нас как раз используются 64bit-ные целые как версия документа (я не совсем согласен как она формируется, но «так уже здесь повелось»), так вот пишется в elasticsearch она правильно, и возвращается в json правильно, но вот в парсере… толи решили сохранить совместимость, толи просто скопипастили код, но все числа при разборе json сначала парсятся из строки как double а потом делается convert в запрошенный приложением тип. С понятными результатами.
все время выводит только на 32- и 64-битные стандарты IEEE S_floating и IEEE T_floating

Смущают обозначения "S_floating", "T_floating". В IEEE стандарте таких терминов нет, гуглежом нашёл через расширенный поиск, это термины DEC (VAX и Alpha). Они точно будут смущать большинство читателей. Для нынешнего мейнстрима, "T" скорее ожидалось бы для ten-byte (специфика x86 и вымершего m68k).


Вангую, что лет через 30, когда этот стандарт станет дефолтным

"Этот" это какой? Binary128? Не думаю, что это произойдёт через 30 лет. Пока что мы видим массовое распространение, например, binary16 в machine learning...

Смущают обозначения «S_floating», «T_floating». В IEEE стандарте таких терминов нет,

Возможно, это какой-то внутренний стандарт Intel или даже Intel фортрана. У меня они используются в справке во всех местах, где упоминается разрядность, вместе со ссылками на IEEE. Честно сказать, мне даже не пришло в голову проверять эти ссылки. Я ведь не особо спец в этих нюансах. Думал, что это просто моя безграмотность, а у умных людей эти обозначения от зубов отскакивают… Буду иметь в виду.

«Этот» это какой? Binary128? Не думаю, что это произойдёт через 30 лет.

Возможно, я чересчур оптимист ;-)
А вообще, было бы интересно посмотреть — что будет через 30 лет? В 1990-м, сидя в высокогорном ауле за терминалом PDP-11, я и представить себе не мог все сегодняшнее ;-) Прямо хоть пари заключай ;-))) Только боюсь, через 30 лет я уже не смогу ни цокнуть языком в случае выигрыша, ни получить заслуженный щелбан по носу, если вдруг проиграю… Да и свои шансы на выигрыш такого пари я оцениваю намного меньше, чем 99% ;-))
UFO just landed and posted this here
Автор статьи бахвалится. Потратил кучу времени, чтобы понять числа с плавающей запятой? Ну-ну.
Сразу видно — не математик, когда начал что-то там мусолить про перегибы двух соседних чисел…
Третий баг — типичная ошибка тех, кто строит счётчики воды/электроэнергии/попугаев на переменных с плавающей запятой. Пока в счётчике малое число, все работает, но позже приращения перестают работать. К большому числу нельзя прибавлять малое в системах точного счета, переходи на целочисленное сложение — это знает каждый.
Не обобщайте так широко. Я вот, хоть и знаю про ограниченность чисел с плавающей точкой, не догадывался про возможное веселье с беконечным циклом.
Так что определённую пользу статья всё же принесла.

Я давно читаю автора в оригинале (на RSS подписан). Его статьи почти все переведены на хабре и очень интересны. Конечно, про числа с плавающей точкой знают почти все, но также почти все и сами совершали те или иные ошибки. Например, в дотнете в BigInteger лет пять назад сам лично исправлял ошибку (логарифм неправильно считался). Даже из этой статьи я вынес полезное — не знал про функцию nextafter — заколхозил бы своё. И я видел даааалеко не одну БД, где люди деньги (!) во флоатах считали.
Еще момент: конкретно эта статья — только первая часть из трёх про числа с плавающей точкой, поэтому лучше было бы указать это в заголовке.

В данном случае мы сразу объединили все 3 части.

А, да, извините, не заметил. Посмотрел, что ссылка на ч.1 и отметил. А так как читал оригинал, то не вчитывался. Еще раз извините. Спасибо за перевод.

Sign up to leave a comment.