Это связано с тем, как компьютеры представляют floating point numbers.
Это все действительно в двоичном формате, но давайте притворимся, что оно работает с номерами оснований 10, потому что нам гораздо легче относиться к ним.
Число с плавающей запятой выражается в форме 0.x*10^y
где x - это 10-значное число (здесь я опускаю конечные нули), а y - показатель степени. Это означает, что число 1.0 выражается как 0.1*10^1
, а число 0,1 - 0.1*10^0
.
Чтобы добавить эти два номера вместе, мы должны убедиться, что они имеют одинаковый показатель степени. Мы можем сделать это легко, сдвинув числа назад и вперед, то есть мы изменим 0.1*10^0
на 0.01*10^1
, а затем добавим вместе, чтобы получить 0.11*10^1
.
Когда мы 0.1*10^1
и 0.1*10^-19
(1e-20) мы сместится 0.1*10^-19
20 шагов, а это означает, что 1 будет выходить за пределы диапазона нашего 10 числа цифр, поэтому мы в конечном итоге с 0.1*10^1 + 0.0*10^1 = 0.1*10^1
.
Причина вы в конечном итоге с 1e-20 в последнем примере, потому что сложение производится слева направо, поэтому мы вычитаем 0.1*10^1
от 0.1*10^1
заканчивая 0.0*10^0
и добавить 0.1*10^-19
к тому, который представляет собой особый случай, когда мы не нужно менять ни одну из них, потому что одна из них ровно равна нулю.
@chepner: Нет, это коммутативно. Нам также потребуется ассоциативность для выполнения преобразований '(x + e) -x'->' x + (ex) '->' x + (- x + e) '->' (x + -x) + e'-> '(хх) + é'. – user2357112
Итак: в случае e + x-x добавление будет (e + x) = 1 (ближайшее представимое число), за которым следует 1-1 = 0 (ближайшее представимое число). Правильно? –
@ Хосе: Правильно. – user2357112