Почему сумма чисел с плавающей точкой с точными значениями все еще зависит от порядка? - PullRequest
0 голосов
/ 01 июня 2018

Предположим, у меня есть 3 числа с плавающей точкой, которые могут быть точно представлены числом с плавающей точкой:

var a=0.1000000000000000055511151231257827021181583404541015625;
var b=0.200000000000000011102230246251565404236316680908203125;
var c=0.299999999999999988897769753748434595763683319091796875;

они являются фактическим значением 0,1,0,2 и 0,3 хранятся в плавающей точке.Я думаю, что a + b + c должно быть равно c + b + a, потому что a, b и c уже округлены и являются точным значением, их сумма не должна зависеть от порядка, но теперь я проверял, что это не так:

var a=0.1000000000000000055511151231257827021181583404541015625;
var b=0.200000000000000011102230246251565404236316680908203125;
var c=0.299999999999999988897769753748434595763683319091796875;
console.log(a+b+c==c+b+a);

В чем причина?

Примечание: я не спрашиваю о Не работает ли математика с плавающей запятой? , потому что 0,1000000000000000055511151231257827021181583404541015625 этоуже точное значение в числе с плавающей запятой (некоторые числа с плавающей запятой могут быть представлены без ошибок округления, например, 0,5,0,75 и 0,375, см .: Является ли жесткий код с плавающей запятой точным, если он может быть представлен двоичным форматом в IEEE 754? ).

Мое предположение: a, b и c не имеют ошибок округления, поэтому их сумма также не должна иметь ошибок округления, совсем как

1+2+3 == 3+2+1
0.5+0.375+0.25 == 0.25+0.375+0.5

, но теперь a + b + cне в этом, что плохого в моем предположении здесь?

Ответы [ 2 ]

0 голосов
/ 01 июня 2018

Я предполагаю, что промежуточные значения сложения могут иметь разные ошибки округления.Например, a + b может привести к ошибке округления.И b + c может и не быть, или результирующее значение может вызвать ошибку плавающего типа другого типа при добавлении с окончательным значением.Добавление скобок делает порядок операций и промежуточных значений более понятным:

(a + b) + c

(c + b) + a

0 голосов
/ 01 июня 2018

Суммы не точны

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

Арифметика с плавающей точкой использует некоторое количество цифр, которое является фиксированным для формата (например,24 двоичные цифры для float).Математическая сумма двух 24-значных чисел может иметь 25 цифр и поэтому требует округления для представления в пределах 24 цифр (и показателя степени).

Кроме того, когда добавляются два числа с разными показателями, цифры одного равнысмещение относительно другого.Сумма может иметь дополнительные цифры из-за смещения и снова должна быть округлена.

При добавлении чисел в разных порядках результирующие округления могут отличаться.

Примеры неточных сумм

В этих примерах используются трехзначные двоичные значения.

В этом примере сложение переносится в новый столбец:

 1.10 • 2<sup>3</sup>
 1.01 • 2<sup>3</sup>
――――――――――
10.11 • 2<sup>3</sup> Exact sum, too many digits, must be rounded.
11.0  • 2<sup>3</sup> Sum rounded to three digits.
1.10  • 2<sup>4</sup> Rounded sum, exponent adjusted to normalize significand.

В этом примере числа имеют разные показатели степении корректировка для этого переводит цифры в новые столбцы:

 1.11 • 2<sup>3</sup>
 1.01 • 2<sup>5</sup>   Different exponent requires adjustment.

 0.0111 • 2<sup>5</sup> Adjusted to match exponent.
 1.01   • 2<sup>5</sup>
――――――――――――
 1.1011 • 2<sup>5</sup> Exact sum, too many digits, must be rounded.
 1.11   • 2<sup>5</sup> Rounded sum.

Примеры неассоциативных сумм

Теперь мы можем посмотреть на добавление трех чисел по-разному и увидеть, что разные суммыпроизв.

Сравним (1,10 • 2 0 + 1,10 • 2 0 ) + 1,00 • 2 4 ) с 1,10 • 2 0 + (1,10 • 2 0 + 1,00 • 2 4 ).

Для первого экспресса мы добавляем первый и второй операнды, затем третий:

Add first and second operands:
 1.10 • 2<sup>0</sup> First operand.
 1.10 • 2<sup>0</sup> Second operand.
――――――――――
11.00 • 2<sup>0</sup> Exact sum, too many digits, must be rounded.
11.0  • 2<sup>0</sup> Rounded sum, must be normalized.
1.10  • 2<sup>1</sup> Normalized, rounded sum.

Add previous result and third operand:
 1.10 • 2<sup>1</sup> Previous result.
 1.00 • 2<sup>4</sup> Third operand.

Exponents do not match, so adjust and then add:
 0.00110 • 2<sup>4</sup> Previous result adjusted to match exponent.
 1.00    • 2<sup>4</sup> Third operand.
――――――――――――
 1.00110 • 2<sup>4</sup> Exact sum, too many digits, must be rounded.
 1.01    • 2<sup>4</sup> Rounded sum.

Для второго выражения добавляем второй и третий операнды, then первое:

Add second and third:
 1.10    • 2<sup>0</sup> Second operand.
 1.00    • 2<sup>4</sup> Third operand.

Exponents do not match, so adjust, then add:
 0.000110 • 2<sup>4</sup> Second operand adjusted to match exponent.
 1.00     • 2<sup>4</sup> Third operand.
――――――――――――――
 1.000110 • 2<sup>4</sup> Exact sum, too many digits, must be rounded.
 1.00     • 2<sup>4</sup> Rounded sum.

Add first operand and previous result:
 1.10     • 2<sup>0</sup> First operand.
 1.00     • 2<sup>4</sup> Previous result.

Exponents do not match, so adjust and then add:
 0.000110 • 2<sup>4</sup> First operand adjusted to match exponent.
 1.00     • 2<sup>4</sup> Previous result.
―――――――――――――
 1.000110 • 2<sup>4</sup> Exact sum, too many digits, must be rounded.
 1.00     • 2<sup>4</sup> Rounded sum.

Первое выражение дает 1,01 • 2 4 , а второе выражение дает 1,00 • 2 4 .Поэтому порядок добавления операндов влияет на результат.

...