JavaScript, кажется, делает с плавающей запятой неправильно (по сравнению с C) - PullRequest
1 голос
/ 17 мая 2019

Из всего, что я смог найти в Интернете, JavaScript якобы использует двойные значения IEEE 754 для своих чисел, но я нашел числа, которые могут работать в двойных Си, но не в JavaScript.Например,

#include <stdio.h>

int main(){
    double x = 131621703842267136.;
    printf("%lf\n", x);
}

печатает 131621703842267136.000000 ПРИМЕЧАНИЕ. В более ранней версии вопроса я скопировал неправильное число для C, но в JavaScript

console.log(131621703842267136)

выводит 131621703842267140.Из всего, что я читал в Интернете, как двойные C, так и числа JavaScript являются 64-разрядными числами с плавающей запятой, поэтому я очень озадачен, почему они будут выводить разные результаты.Есть идеи?

1 Ответ

2 голосов
/ 17 мая 2019

Преобразование JavaScript по умолчанию Number в строку дает достаточно десятичных цифр, чтобы однозначно отличить Number.(Это вытекает из шага 5 в п. 7.1.12.1 спецификации языка ECMAScript 2018 , которую я немного объясняю здесь .) Форматирование с помощью console.log не рассматривается в ECMAScriptспецификации, но, скорее всего, Number преобразуется в строку с использованием тех же правил, что и для NumberToString.

Поскольку остановка на десятичной цифре, производящая 131621703842267140, достаточна для того, чтобы отличить число с плавающей запятой от егодва соседних представимых значения, 131621703842267120 и 131621703842267152, на этом JavaScript останавливается.

Вы можете запросить дополнительные цифры с помощью toPrecision;следующее производит «131621703842267136.000»:

var x = 131621703842267136;
console.log(x.toPrecision(21))

(Обратите внимание, что 131621703842267136 точно представлен в базовом 64-битном двоичном формате IEEE-754, который JavaScript использует для Number, а многие реализации C используют для doubleТаким образом, в этом вопросе нет ошибок округления из-за формата с плавающей запятой. Все изменения являются результатом преобразований между десятичной и плавающей запятой.)

Стандарт C не отвечает требованиям к форматированию с плавающей запятой,но производство «131621703737409536.000000» для 131621703842267136 нарушает их.Это регулируется этим предложением в C 2018 (и 2011) 7.21.6.1 13:

В противном случае исходное значение ограничено двумя соседними десятичными строками L <<em>U , оба имеют DECIMAL_DIG значащих цифр;значение результирующей десятичной строки D должно удовлетворять L D U с дополнительным условием, что ошибка должна иметьправильный знак для текущего направления округления.

DECIMAL_DIG должно быть не менее десяти, согласно 5.2.4.2.2 12. Число 131621703 8 42267136 (жирным шрифтом отмечен десятыйцифра) ограничивается двумя смежными десятизначными строками «131621703 8 00000000» и «131621703 9 00000000».Строка «131621703 7 37409536.000000» не находится между ними.

Это также не может быть результатом реализации C, использующей другой формат с плавающей запятой для double, как 5.2.4.2..2 требует, чтобы формат был достаточным для преобразования не менее десяти десятичных цифр в double и обратно в десятичную без изменения значения.

...