Обращаясь к денежной стоимости, безопасно ли делить число на 100? - PullRequest
4 голосов
/ 12 марта 2019

В коде репозитория, в модуле, разработанном другой командой, я обнаружил, что происходит конвертация цены из центов в евро, просто деление числа на 100.

Код написан на Javascript, поэтому он использует IEEE 754 стандарт.

Я знаю, что небезопасно обрабатывать денежные значения как числа с плавающей запятой, но мне было интересно, безопасен ли этот случай перед отправкой задачи другой команде.

Пока что я не обнаружил ни одного случая, когда деление целого числа на 100 дает неточный результат. Пойдем дальше: 100 это просто 2*2*5*5.

Мы знаем, что деление числа на 2 безопасно, поскольку оно просто равно смещению позиции.

Таким образом, мы можем легко сказать, что, если существует число, которое не делится точно на 5, то деление на 100 не является точным.

Я провел много тестов и не нашел ни одного из этих чисел, но я далек от теоретической демонстрации тезиса.

Итак, делится ли число на 100 в стандарте IEEE 754?

Ответы [ 2 ]

1 голос
/ 13 марта 2019

Десятичное число с плавающей запятой с 15 значащими цифрами точности преобразуется в 64-разрядное двоичное число с плавающей запятой (Number в JavaScript) и обратно в десятичное число без потери точности. Обратите внимание, что хотя двоичное число может не точно хранить десятичное число, оно имеет больше битов точности (для его представления требуется не менее 17 десятичных значащих цифр) и преобразуется с округлением обратно до исходного десятичного числа. См. см. https://www.exploringbinary.com/number-of-digits-required-for-round-trip-conversions/ для получения полной информации.

Когда вы делите на 100, двоичный результат все еще имеет 64-битную точность с возможной ошибкой в ​​единице наименьшей точности (наименьший бит манитиссы), если результат не опустится до 0 (см. What Every Computer Scientist) Следует знать об арифметике с плавающей точкой для получения полной информации.). Это все еще конвертирует с округлением до правильного числа в пределах 15 значащих десятичных цифр.

Другими словами, если ваши десятичные числа имеют не более 15 значащих цифр, то деление их на 100 сохраняет эту точность.

например. попробуйте 123456789012345 / 100 и 0.000123456789012345 / 100 в консоли браузера (оба эти числа имеют 15 значащих десятичных цифр точности) - эти деления возвращают правильные десятичные числа в пределах 15 значащих десятичных цифр:

123456789012345 / 100
1234567890123.45

0.000123456789012345 / 100
0.00000123456789012345
0 голосов
/ 13 марта 2019

Если x - это целое число из 15 десятичных цифр, то преобразование x в JavaScript Number, деление на 100 и преобразование результата в число с 15 значащимидесятичные цифры дают ровно x / 100.Далее следует доказательство.

Примечания:

  • Преобразование результата деления в число с 15 значащими десятичными цифрами дает в точности x / 100.Фактический результат деления, хотя и в формате Number, обычно не будет точно x / 100.Например, 73/100 дает 0,729999999999999982236431605997495353221893310546875.
  • Преобразование результата деления в больше , чем 15 значащих десятичных цифр, также обычно не даст x / 100, так какдополнительные цифры могут показать разницу, как показано для .73 выше.(И, конечно же, использование меньшего числа цифр может оказаться недостаточным для представления x / 100.) Таким образом, если требуется передать точно x / 100 другому процессу, это должно бытьсделано ровно с 15 значащими десятичными цифрами (или с некоторыми другими мерами по исправлению ошибки).
  • Приведенное ниже доказательство относится к 15-значным целым числам x , а не к другим 15-значным десятичным знакам(например, цифры с 15 десятичными цифрами, за которыми следуют один или несколько нулей или цифры, начинающиеся с десятичной точки, за которой следуют несколько нулей и 15 значащих цифр).

Предварительные сведения

JavaScript - этореализация ECMAScript, указанная в Ecma-262 и ISO / IEC 16262. В пункте 6.1.6 Ecma-262 указывает, что базовый 64-битный двоичный формат IEEE-754 используется для ECMAScriptNumber, за исключением того, что используется только один NaN.Раздел 6.1.6 далее описывает используемую арифметику, которая по существу является арифметикой IEEE-754 с округлением до ближайшего, с привязкой к четности.

Базовый 64-разрядный двоичный формат IEEE-754 использует формат с плавающей запятой53-битное значение.

Единица наименьшей точности (ULP) двоичного числа с плавающей запятой - это значение, приписываемое позиции младшего разряда в его значении.(Таким образом, ULP масштабируется с показателем степени.) Измеряется в ULP, все нормальные 53-битные значения находятся в [2 52 ULP, 2 53 ULP).

Для десятичного числа из 15 значащих цифр его ULP в данном документе будет значением, относящимся к положению позиции 15 th , начиная с первой значащей цифры.

Лемма

Сначала мы установим общеизвестный факт, что преобразование числа из 15 значащих десятичных цифр в Number и обратно в 15 значащих десятичных цифр дает исходное число, при условии, что число находится в пределах нормального диапазонаформат Number.

Если x - это число из 15 значащих десятичных цифр (необязательно целое число) в пределах нормального диапазона формата с плавающей запятой (2 -1022 ≤ | x | <2 <sup>1024 ), затем преобразование x в ближайшее значение, представляемое в формате с плавающей запятой, и затем преобразование результатадо 15 значащих десятичных цифриспользует ровно x , когда оба преобразования выполняются с округлением до ближайшего, с привязкой к четному.Чтобы увидеть это, пусть y будет результатом первого преобразования.Если y отличается от x менее чем на ½ ULP, равного x , то x - это 15-значное число, ближайшее к y и, следовательно, должно быть результатом второго преобразования.

IВ первом преобразовании результат y составляет не более ½ ULP от x из-за правила округления.Это относительная точность не более ½ / 2 52 (то есть потенциальная ошибка ½ ULP, деленная на наименьшее значимое значение, которое может быть измерено в ULP).Таким образом, y отличается от x не более чем на одну часть в 2 53 .В худшем случае цифры x могут быть 9999999999999 = 10 15 -1, поэтому ошибка относительно ULP x будет равна (10 15 -1) / 2 53 , что примерно в 0,11 раза превышает ULP x .Таким образом, y всегда отличается от x менее чем на 1/2 от его ULP, поэтому преобразование y обратно в 15 значащих десятичных цифр дает x .

Proof

Если x представляет собой целое число из 15 десятичных цифр, оно точно представляется в формате Number, поскольку формат Number имеет 53биты в его значении и, следовательно, способны точно представлять все целые числа до 2 53 , что составляет около 9,007e15, что более 10 15 .

Таким образомпреобразование x в Number дает в точности x без ошибок.

Затем, по правилам округления арифметических результатов, делим x на 100 дает представимое число, ближайшее к x / 100.Назовите это y .Теперь обратите внимание, что x / 100 - это число, представляемое с 15 значащими десятичными цифрами.(Он может быть записан в научной нотации как x • 10 -2 или в исходном коде как цифры x с суффиксом e-2.) Обратите внимание, чтопреобразование x / 100 в Number также дает y , поскольку преобразование дает, как и деление, число, точно представимое в формате Number, ближайшем к х * * тысяча сто шестьдесят один / 100.По лемме результат преобразования x / 100 в Number и обратно в число, состоящее из 15 значащих десятичных цифр, дает x / 100, и, следовательно, результат преобразования x до Number, затем деление на 100, затем преобразование в 15 значащих десятичных цифр также дает x / 100.

...