Могу ли я вызвать ошибку точности с плавающей запятой? - PullRequest
2 голосов
/ 18 февраля 2020

У меня простой (возможно, наивный) вопрос - я пытаюсь протестировать сценарий, и мне было интересно, возможно ли вызвать ошибку точности с плавающей запятой при разборе строки на число (есть ли число волхвов c) что вызовет FPPE?).

например,

parseFloat("4.015") // = 4.0149999999999994
const foo = 4.015 // = 4.0149999999999994

Или, возможно ли только создать ошибку точности с плавающей запятой в результате операции?

console.log(4.015)
console.log(parseFloat("4.015"))
console.log(4.015 * 100)

1 Ответ

2 голосов
/ 18 февраля 2020

Преобразование числа из десятичного числа в строке в двоичное число с плавающей запятой является операцией, и оно приводит к «ошибкам точности». Если номер источника не может быть представлен в формате назначения, он округляется.

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

В console.log(4.015) десятичное число «4.015» представляет число 4.015. Когда он преобразуется в 64-разрядную двоичную с плавающей точкой IEEE-754, которую использует JavaScript, результат равен 4,01499999999999968025576890795491635799407958984375. (В нем много цифр, но он фактически представлен внутри в форме, эквивалентной 4520488125973135 раз 2 -50 .) Затем, чтобы вывести это на консоль, он преобразуется из двоичной с плавающей запятой в десятичную , При выполнении преобразования JavaScript использует только столько десятичных цифр, чтобы однозначно отличить guish значение от соседних значений, которые могут быть представлены в двоичной форме с плавающей запятой. Результатом является строка «4.015». Таким образом, двоичное значение с плавающей запятой было округлено до другого десятичного значения, что дает ту же строку, что и оригинал. Таким образом, в console.log(4.015) фактически есть две операции преобразования, в обоих из них есть ошибка округления, и поведение программного обеспечения действует, чтобы скрыть ошибки округления.

В console.log(parseFloat("4.015")), то же самое происходит, за исключением того, что первое преобразование выполняется при вызове parseFloat вместо интерпретации 4.015 в исходном коде.

В console.log(4.015 * 100) имеется четыре операции и три ошибки округления:

  • 4.015 преобразуется в двоичную с плавающей запятой, которая имеет ошибку округления, описанную выше.
  • 100 преобразуется в двоичную с плавающей запятой, и ошибки округления нет, потому что 100 представляется в двоичной форме с плавающей запятой.
  • Два двоичных числа с плавающей запятой умножаются, и возникает ошибка округления, приводящая к 401.49999999999994315658113919198513031005859375.
  • Этот результат преобразуется в десятичную строку. В результате получается «401.49999999999994», поскольку нам нужно столько цифр, чтобы отличить guish от двух соседних представимых значений: 401.4999999999998863131622783839702606201171875 и 401.5.

В итоге:

  • Каждая операция, включая преобразования между двоичным и десятичным, может быть подвержена ошибке округления.
  • Стандартное форматирование JavaScript действует, чтобы скрыть некоторые ошибки округления; при круговом переходе от десятичных цифр короче 16 цифр всегда будет получаться исходное число (в пределах конечного диапазона формата).
...