Несмотря на то, что ответ AMA является правильным в том смысле, что округление происходит после каждого добавления, такие же неожиданности могут произойти даже для одной операции (включая умножение):
#include <iostream>
int main()
{
const auto val1 = 0.3444444444444444
, val2 = 0.34444444444444442;
std::cout << (2*val1) << '\n'
<< (2*val2) << '\n';
}
(Если не указано иное, я предполагаю, что IEEE удваивается при стандартном поведении округления.)
В первой строке будет показано 0,6888888888888888 (если вы мне доверяете, чтобы подсчитать для вас, это 15x4 на входе и 15x8 на выходе) без сюрпризов. Мы предполагаем, что во второй строке указана либо дополнительная цифра, возможно, около 4, либо результат не изменился.
В действительности, однако, вторая строка покажет 0,688888888888888 9 . Это удивительно, как можно округлить 4 на последнюю цифру до на следующую старшую цифру? Это противоречит нашему представлению о том, что неравенства сохраняются, когда с обеих сторон применяется положительный масштабный коэффициент. То есть так как 2 <2,5, то 2 * 2 <2 * 2,5, затем 4 <5. Это означает, что для округления в большую сторону (в десятичной системе) в <code>2*val2 потребуется последняя цифра 5, что val2
должно быть интуитивно должно быть не менее 0,3444444444444444 25 для округления вверх.
Проблема здесь в том, что каждая система счисления имеет различное округление входов и выходов. На самом деле, в результате самого умножения не происходит округления даже в двоичном виде, однако округление происходит в обоих преобразованиях системы счисления. Двоичные представления входов:
0,01011000001011011000001011011000001011011000001011001 (val1
)
0,01011000001011011000001011011000001011011000001011011 (val2
)
Умножение на 2 - это просто сдвиг влево на 1, конечно, в двоичном формате, который включает в себя число с плавающей запятой (по крайней мере, если мы игнорируем возможность переполнения), поэтому выходные данные:
0.10110000010110110000010110110000010110110000010110010 (2*val1
)
0.10110000010110110000010110110000010110110000010110110 (2*val2
)
Последний преобразуется обратно в 0,688888888888888 88395 … (обратите внимание, что теперь есть дополнительные 8), который правильно округляется до 0,6888888888888888 9 .
В этом конкретном случае первоначальная причина неожиданного поведения заключается в том, что val2
фактически становится:
0,3444444444444444 419772821675
также с дополнительным 4, который заменяет трейлинг 2, который мы ввели, и который при удвоении вызывает округление вверх в десятичном виде.