После некоторого исследования, я пришел к выводу, что ваш код является НАВЕРНОЕ запутанным float
и double
(или просмотр выходного кода, который отличается от того, что вы на самом деле писали).
Это работает для меня:
#include <iostream>
int main()
{
double lnA = 1448481410.0;
double lnB = 0.75599998235702515;
double lnC = lnA + lnB;
std::cout << std::fixed << "A:" << lnA << " B:" << lnB << " C:" << lnC << std::endl;
}
Производит:
$ ./a.out
A:1448481410.000000 B:0.756000 C:1448481410.756000
Теперь, как сказал Soulsabr в комментарии, если мы будем использовать float
вместо double
, результат отличается:
Только эти линии изменены:
float lnA = 1448481410.0;
float lnB = 0.75599998235702515;
float lnC = lnA + lnB;
$ ./a.out
A:1448481408.000000 B:0.756000 C:1448481408.000000
Это связано с тем, что количество бит в float
, в типичных системах, составляет 32 бита, который делится на 8 бит экспоненты, один бит знака и 23 бита [плюс один скрытый] для мантиссы. поэтому значение равно S * M * 2^E
, где S
- знак, M
- это мантисса, а E
- показатель степени. Размер M
составляет 23 бита, поэтому его можно использовать для описания значений до 8 миллионов. Мы можем сдвинуть значение с помощью E, но независимо от того, какое значение мы выберем, наименьшее значение, которое может меняться внутри числа, - это следующее большее целое число x/8 миллионов от фактического значения. Таким образом, 14 миллионов становятся +/- 2 в наименьшем значении, которое «имеет значение». Добавление 1 или менее не будет иметь никакого эффекта.
Код double
«работает», потому что 64-битный double имеет 53-битную мантиссу, которая позволяет использовать значение +/- 1/2^53 от фактического значения, которое является БОЛЬШИМ большим значением и позволяет более точно вычислять. Но возьмите достаточно большое и достаточно маленькое значение, и мы получим ту же проблему, если они достаточно далеко друг от друга. Это всего лишь вопрос о том, как работают значения с плавающей запятой. У вас так много бит. Существуют «большие математические» библиотеки, которые позволяют большее количество бит («бесконечно», при условии доступности памяти), но, конечно, с большими значениями скорость вычисления уменьшается, а для большинства вещей 1/2^53 из значение «достаточно хорошо».
Edit (на основе комментариев по OP):
Аналогичный эффект на «использовании поплавок» может произойти, если при использовании инструкций x87, ФП устанавливаются на «круглый до 32 бит», что означает, что даже если вычисление производится с 64-битными значениями с плавающей запятой, промежуточные результаты округляются до 32-битной точности. Для комментариев выше, это, кажется, определенный программный продукт, который делает некоторые «Магические» для достижения этого, и есть простой обходной путь.
введите полный код –
Опубликуйте [MCVE], который воспроизводит поведение, о котором вы говорите. –
[lnA - lnC is -0.756, not 2] (http://cpp.sh/2l3z). – emlai