为什么不添加这些浮点数呢?

Cpt*_*nic -4 c++ windows floating-point

我知道这些浮点问题可能是堆栈溢出时最常问的问题,但我找不到看起来像我的东西.在windows(visual studio)编译为32位,如果我这样做:

double lnA = 1448481410.0;
double lnB = 0.75599998235702515;
double lnC = lnA + lnB; 
Run Code Online (Sandbox Code Playgroud)

我得到lnC = 1448481408.0000000.由于浮点表示,我可以理解一个小的差异,但我不明白为什么lnA - lnC == 2?

更新:所以这是使用Visual Studio 2010的实际输出:这是一个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);
Run Code Online (Sandbox Code Playgroud)

A = 1448481410.000000 B = 0.756000 C = 1448481408.000000 A - C = 2.000000

UPDATE2:在尝试制作如下所示的最小完整示例时,我没有看到同样的问题.只有当它是我的大型应用程序的一部分.有任何想法吗?

#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;
 }
Run Code Online (Sandbox Code Playgroud)

Mat*_*son 5

经过一番调查后,我得出的结论是,您的代码可能会令人困惑,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;
}
Run Code Online (Sandbox Code Playgroud)

生产:

$ ./a.out
A:1448481410.000000 B:0.756000 C:1448481410.756000
Run Code Online (Sandbox Code Playgroud)

现在,正如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
Run Code Online (Sandbox Code Playgroud)

这是因为float在典型系统中,a的比特数是32比特,它被分成8比特的指数,1比特的符号和23比特[加上一个隐藏]用于尾数.所以值是S * M * 2^E,S符号在哪里,M是尾数,E是指数.大小M为23位,因此可用于精确描述高达约8百万的值.我们可以使用E来移动值,但无论我们选择什么值,在数字内可以改变的最小值是x/8百万实际值的下一个更大的整数.因此,"有所作为"的最小值中有1400万变为+/- 2.添加1或更少将完全没有效果.

double代码"作品",因为一个64位双具有53位尾数,其允许值设定为+/- 1/^的实际值,这是一个更大的值的53,并且允许进行更精确的验算.但要取得足够大和足够小的价值,如果它们足够远,我们就会遇到同样的问题.这只是浮点值如何工作的问题.你只有这么多位.有"大数学"库允许更多位,("无限",受内存可用),但当然,值越大,计算速度越低,对于大多数事情,1/2 ^ 53价值"足够好".

编辑(根据OP的评论):

如果在使用x87指令时将FPU设置为"舍入到32位",则表示即使使用64位浮点值进行计算,也会发生与"使用浮点数"类似的影响,中间结果舍入为32位精度.根据上面的评论,这似乎是一个特殊的软件产品,做了一些"魔术"来实现这一点,并有一个简单的解决方法.