Comments 19
по той же причине это на самом деле не баг.
Это не баг, просто javascript — язык для небольших скриптов на веб-страницах, когда он разрабатывался — никто и представить не мог, что кто-то будет писать на этом программы. Но мир сошёл с ума и теперь его пихают везде. Ещё бы из bat-файлов программы писали.
json = JSON.parse(‘{“x”: 2940078943461317278}’); alert(json[‘x’]);
Это очень небольшой скрипт для вебстраницы. Практически даже минимальный.
Скромность масштаба программы и магнитуды используемых в ней чисел — две большие разницы, как говорят в одном славном приморском городе.
Другой пример, — значения хешей для технических надобностей неглобального характера (всякие GUID-подобные идентификаторы, например) часто приводят к int64. Опять же потребуется их «примитивно» вывести с помощью JS — очень не всякий подумает, что с ними придётся работать как со строками…
Другими словами — вариантов, где возникнут большие «числа» на самом деле предостаточно даже в очень простых и примитивных вариантах использования. А сравнивать современный JS с тем, что было изначально выпущено… Какой смысл? Язык эволюционирует.
… просто javascript — язык для небольших скриптов на веб-страницах, когда он разрабатывался — никто и представить не мог, что кто-то будет писать на этом программы. Но мир сошёл с ума и теперь его пихают везде. Ещё бы из bat-файлов программы писали.
Не очень понятно как это соотносится со сказанным в статье. Так-то в JS для представления чисел используется float64, диапазон целых в котором сильно больше (примерно в 4 миллиона раз), чем скажем в int32, который для представления целых чисел использовался десятилетиями. Ошибку в алгоритме вычисления среднего арифметического так и вовсе только через 20 с лишним лет нашли.
… должно возвращаться целочисленное значение 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, когда этот стандарт станет дефолтным, а языки, позволяющие (требующие?) явно указывать разрядность числа, уйдут глубоко в андерграунд, столкновение с описанными в статье багами (на новом уровне точности) будет вызывать настоящий шок, так как в мэйнстриме практически не останется специалистов, способных в них разобраться, объяснить и поправить…
У нас как раз используются 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% ;-))
Сразу видно — не математик, когда начал что-то там мусолить про перегибы двух соседних чисел…
Третий баг — типичная ошибка тех, кто строит счётчики воды/электроэнергии/попугаев на переменных с плавающей запятой. Пока в счётчике малое число, все работает, но позже приращения перестают работать. К большому числу нельзя прибавлять малое в системах точного счета, переходи на целочисленное сложение — это знает каждый.
Так что определённую пользу статья всё же принесла.
Я давно читаю автора в оригинале (на RSS подписан). Его статьи почти все переведены на хабре и очень интересны. Конечно, про числа с плавающей точкой знают почти все, но также почти все и сами совершали те или иные ошибки. Например, в дотнете в BigInteger лет пять назад сам лично исправлял ошибку (логарифм неправильно считался). Даже из этой статьи я вынес полезное — не знал про функцию nextafter
— заколхозил бы своё. И я видел даааалеко не одну БД, где люди деньги (!) во флоатах считали.
Еще момент: конкретно эта статья — только первая часть из трёх про числа с плавающей точкой, поэтому лучше было бы указать это в заголовке.
Браузер и числа с плавающей запятой