C++ 为什么';这些浮点数加起来有什么意义?

C++ 为什么';这些浮点数加起来有什么意义?,c++,windows,floating-point,C++,Windows,Floating Point,我知道这些浮点问题可能是stack overflow中被问得最多的问题,但我找不到与我类似的问题。在windows(visual studio)中编译为32位,如果我这样做: double lnA = 1448481410.0; double lnB = 0.75599998235702515; double lnC = lnA + lnB; 我得到lnC=1448481408.0000000。由于浮点表示,我可以理解一个小差异,但我不理解为什么lnA-lnC==2 更新: 下面是使用Vis

我知道这些浮点问题可能是stack overflow中被问得最多的问题,但我找不到与我类似的问题。在windows(visual studio)中编译为32位,如果我这样做:

double lnA = 1448481410.0;
double lnB = 0.75599998235702515;
double lnC = lnA + lnB; 
我得到lnC=1448481408.0000000。由于浮点表示,我可以理解一个小差异,但我不理解为什么lnA-lnC==2

更新: 下面是使用VisualStudio2010的实际输出:这是一个MFC应用程序,这就是我使用TRACE的原因

double lnA = 1448481410.0;
double lnB = 0.75599998235702515;
double lnC = lnA + lnB;

TRACE("A = %f B = %f C = %f A - C = %f\n",lnA, lnB, lnC, lnA - lnC);
A=1448481410.000000 B=0.756000 C=1448481408.000000 A-C=2.000000

更新2:在尝试制作一个最小的完整示例(如下面所示)时,我没有看到相同的问题。只有当它是我的大型应用程序的一部分时。有什么想法吗

#include <iostream>

int main() {
    double lnA = 1448481410.0;
    double lnB = 0.75599998235702515;
    double lnC = lnA + lnB;

    std::cout << "A: " << lnA << "B: " << lnB  << "C: " << "Diff: " << lnA - lnC << std::endl;
    return 0;
 }
#包括
int main(){
双低噪声放大器=1448481410.0;
双lnB=0.75599998235702515;
双lnC=lnA+lnB;

std::cout经过一些调查,我得出结论,您的代码可能混淆了
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;
}
现在,正如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
这是因为在典型系统中,
浮点
中的位数为32位,分为8位指数、1位符号和23位[加上1位隐藏]对于尾数。因此值是
S*M*2^E
,其中
S
是符号,
M
是尾数,
E
是指数。
M
的大小是23位,因此它可以用来精确描述高达800万的值。我们可以使用E来移动值,但无论我们选择什么值,都是小的可以在该数字内改变的t值是下一个较大的整数,即实际值的x/800万。因此,1400万变为+/-2,即“产生差异”的最小值。加上1或更少都不会产生任何效果

double
代码“起作用”因为一个64位的双精度浮点运算有一个53位的尾数,它允许值是实际值的+/-1/2^53,这是一个更大的值,允许更精确的计算。但是如果值足够大和足够小,如果它们之间的距离足够远,我们会遇到同样的问题。这只是浮点值如何工作的问题。你只需要有一些“大数学”库允许更多的位(“无限”,取决于内存可用),但当然,值越大,计算速度越慢,对于大多数情况,1/2^53的值“足够好”

编辑(基于OP的评论):


如果在使用x87指令时,FPU设置为“舍入到32位”,则可能会出现与“使用浮点”类似的效果,这意味着即使使用64位浮点值进行计算,中间结果也会舍入到32位精度。根据上面的注释,这似乎是一个特定的软件产品,它可以执行一些操作“魔术”实现了这一点,有一个简单的解决方法。

请将完整的代码放在一个复制您所关心的行为的位置。。这些问题需要附有有关如何确定值为
2
的信息。可能您的输出语句是错误的(
printf
使用错误的格式说明符,例如),可能你在某个地方转换/强制转换不正确,可能你的调试器关闭了,等等,仅仅发布3行有效的声明和计算并不能提供这些信息。请注意
#定义双浮点数
或类似内容。除非你解释为什么双浮点数代替浮点数工作,否则这对他/她没有帮助。我看不到任何信息使用
float
的离子?[通用术语“浮点”除外]我说这不是一个答案,所以请不要因为这个原因否决它!你绝对正确。我从两个不同的问题中得到了我的答案。我对此表示歉意。如果这不是一个答案,你可以编辑它,并将其作为一个社区维基答案,以避免否决票。
float lnA = 1448481410.0;
float lnB = 0.75599998235702515; 
float lnC = lnA + lnB;


$ ./a.out
A:1448481408.000000 B:0.756000 C:1448481408.000000