lua, js - сравнение целых чисел учитывая что они хранятся как double
Известно, что как lua (по умолчанию) так и javascript хранят все числа как IEEE double. Известно также что результаты вычислений во floating point нельзя проверять на совпадаение, т.к. 0.1 + 0.2 != 0.3.
Вопрос - а как в этих языках реализуется целочисленная арифметика? Какие есть гарантии по поводу неё? Тест на js показывает, что (0.7 + 1.9 == 2.6) === false, но (7 + 19 == 26) === true, и даже (7.0 + 19.0 == 26.0), хотя 7 ровно также непредставимо в качестве конечной двоичной дроби как и 0.7. Ясно что оно не сравнивает числа с epsilon допуском, иначе в первом случае было бы true, значит или там хранится флаг целого числа (причём 7.0 тоже считается целым), или результат, достаточно близкий к целому (с достаточным числом нулей после запятой) считается целым. Где про это почитать чтобы не влететь в неожиданности с целыми числами вообще, а в особенности с большими целыми числами, где начнёт сказываться ограничение точности double?
емнип если число целиком влезает в мантиссу то все ок, это какраз в стандарте есть, потому шо 7.0 шо 7 это у тебя не дробь а целое число, а 0.7 дробь
number in Lua is similar to Neko float. Both are by default double-precision IEEE floating point values. And both are customizable to use single precision or even fixed point arithmetics.
это может считаться ответом?
О, спасибо. Я почему-то думал что в IEEE мантисса представляет дробную часть из диапазона [0, 1), а оказывается она вполне себе обычное целое число. Получается что от -2^52+1 до 2^52-1 double можно свободно складывать, вычитать и умножать как целые числа?
IEEE мантисса представляет дробную часть из диапазона
это в нормальзованной, очевидно что если ее всегда нормализовывать то цифры 7 у нас не будет, потому полагаю иногда ее денормализуют. Скорее всего это зависит от реализации в ЯП.
Очевидно что если в js у нас «целые» числа станут «дробными» то множество веб-программистов хватит удар, потому видимо решено было до 2^52 их не шокировать
бгг http://www.yur.ru/science/computer/IEEE754.htm я пока не прочитал целиком но заголовок доставляет
я идиот
все верно, число то представляет дрбную часть, но двоичной дроби, т.е.
Вопрос - а как в этих языках реализуется целочисленная арифметика?
ЕМНИП intel гарантирует, что её FPU НЕ ошибаются, если числа <2⁶⁴, и если ты их не делишь не нацело. Т.е. 9/3 делить можно, и 123456789/9 тоже можно.
Ну а дробные (2.6 это неправильная дробь, и в двоичном виде бесконечная) - как карта ляжет.
Где про это почитать чтобы не влететь в неожиданности с целыми числами вообще, а в особенности с большими целыми числами, где начнёт сказываться ограничение точности double?
угу. Причём первая ВСЕГДА 1, и её потому НЕ хранят.
(кроме нуля). Получается 011001100110011001100110011001100…
IEEE-754 гарантирует, что если число представимо как m*2^e (где m и e целые и заранее ограничены в количестве бит), то оно должно быть представлено именно так. Если нет — то заранее оговоренное округление до представимого вида. Про колоду и положения карт там вроде не упоминается.
Про колоду и положения карт там вроде не упоминается.
конечно, не упоминается. Сам говоришь - округляется, но не говоришь - ЧТО будет округляться? А от этого ЧТО, зависит - СКОЛЬКО получится. 1.2+3.8 Вполне может получится и 4.(9), что очевидно НЕ равно 5. Сторона, куда округляется число зависит от первого отброшенного бита, а этот бит зависит разве что от погоды на Марсе. Но что самое обидное, 1.2 ты в нормальном виде НЕ представишь, ибо это 6/5. (1.0011001100110011001100110011001100), вероятность того, что отброшенный бит равен 1 равна ровно ½, 4.(9) получается тоже с вероятностью ½. Хоть ты 52й бит отбрасывай, хоть 5552й. Не важно.
1. Давай сейчас запусти в большом цикле скрипт/программу/whatever, который складывает double 1.2 и 3.8 и посмотри к чему там сходятся вероятности получить 4.(9) и 5, ок?
2. IEEE-754 одинаково ведет себя на разных платформах, и не зависит от погоды на марсе. То, что у тебя в руках не 1.2, а лишь его неточное представление, не значит, что возникают какие-то вероятности и неопределенности.
Образованному человеку, разбирающемуся в теме понятно, что ты хочешь сказать, можешь не разжевывать. Но в качестве обучающего материала на форуме шаманские объяснения использовать не нужно.
1. Давай сейчас запусти в большом цикле скрипт/программу/whatever, который складывает double 1.2 и 3.8 и посмотри к чему там сходятся вероятности получить 4.(9) и 5, ок?
не ОК. Голову включи - результат зависит от того, КАКОЙ бит ты отбрасываешь: 45456й или 45457й? Если всегда будешь один и тот же бит отбрасывать - результат будет одинаковый.
Ну и к тому же, разумный компилятор считает 1.2+3.8 константой 5. Целой, ЧСХ. Потому в коде вообще никаких вычислений не будет.
2. IEEE-754 одинаково ведет себя на разных платформах, и не зависит от погоды на марсе. То, что у тебя в руках не 1.2, а лишь его неточное представление, не значит, что возникают какие-то вероятности и неопределенности.
стандарт ничего не говорит о том, ЧЕМУ равно 1.2, и даже как раз наоборот - говорит о том, что ему(стандарту) это неведомо, ибо 1.2 это нецелое число, и в конечную дробь его преобразовать можно только с потерей точности. Также в стандарте не написано, КАКАЯ КОНКРЕТНО будет потеря, даже не написано того, будет-ли 1.2 больше или меньше того, что получится.
IRL это значит только то, что если на i5 получилось 4.(9), то на i7 _может_ получится 5.0. Мало того, результат также зависит от опций компилятора, ибо считать дробные числа можно по разному. В 32х битной версии компилятор любит FPU, а в 64х битной - SSE2. В стандарте не сказано, чем они должны отличаться, и должны-ли. Максимальная погрешность указана, а вот абсолютное значение - увы. Даже знак ошибки неизвестен.
Но в качестве обучающего материала на форуме шаманские объяснения использовать не нужно.
Почему же? И кстати, IRL это очень похоже на магию с приворотами и Папюсом - если писать так программу, то она действительно работает в соответствии с тем, в каком доме Меркурий.
вот например здесь: lua, js - сравнение целых чисел учитывая что они хранятся как double (комментарий) другой(я надеюсь) ананимус советует воспользоваться методом тыка в качестве пруфа, а я ему объясняю, что если реципиент умирает в корчах, то это вовсе не обязательно из-за шаманских ритуалов.
Вполне ок, как по мне. Цель — проверить детерминизм при равных условиях. Лень или страшно?
стандарт ничего не говорит о том, ЧЕМУ равно 1.2, и даже как раз наоборот - говорит о том, что ему(стандарту) это неведомо, ибо 1.2 это нецелое число, и в конечную дробь его преобразовать можно только с потерей точности. Также в стандарте не написано, КАКАЯ КОНКРЕТНО будет потеря, даже не написано того, будет-ли 1.2 больше или меньше того, что получится.
Действительно, он описывает представимость чисел в ограниченной форме. Соответственно, твой компилятор прекрасно знает, какие байты положить в память, чтобы (пусть и неточно) представить
1.2. Это касательно конверсии char * -> double. Касательно вычислений — для каждой операции и ее операндов определен результат и погрешность. Берешь 6 и 5, делишь их друг на друга в 80-битном IEEE-754 FPU (как у интела например), и получаешь предсказуемый результат. "(Операция, операнды, флаги поведения) -> (результат, погрешность)".
А то, что от последовательности операций может плавать и по-разному копиться погрешность, это и дураку ясно. То же самое наблюдается и для целочисленной арифметики, только вокруг нее почему-то не напускают столько шаманского дыма.
Вполне ок, как по мне. Цель — проверить детерминизм при равных условиях. Лень или страшно?
я просто ЗНАЮ, что получится. Получится одно и то же, при всех равных. Это быдлокод называется - код, который работает только на компьютере автора-быдлокодера.
получаешь предсказуемый результат. "(Операция, операнды, флаги поведения) -> (результат, погрешность)«.
да. результат предсказуемый. 5±2¯⁵⁰. Ошибка очень малая, и нам это точно известно. Но НЕИЗВЕСТНО КАКАЯ ИМЕННО.
А то, что от последовательности операций может плавать и по-разному копиться погрешность, это и дураку ясно. То же самое наблюдается и для целочисленной арифметики, только вокруг нее почему-то не напускают столько шаманского дыма.
нет. Для целочисленной арифметики нет округления. Округление == потеря информации. Это сложно понять? Когда ты информацию теряешь, получаешь в результате НЁХ. Это как деление на ноль - при умножении на ноль ты теряешь число, а деление - восстановление информации после умножения. Деление на ноль - попытка восстановить безвозвратно потерянное.