C ++浮点精度损失:3015 / 0.00025298219406977296
-
22-09-2019 - |
题
的问题。
的Microsoft Visual C ++编译器2005,32位的Windows XP SP3,AMD 64 X2处理器。
代码:
double a = 3015.0;
double b = 0.00025298219406977296;
//*((unsigned __int64*)(&a)) == 0x40a78e0000000000
//*((unsigned __int64*)(&b)) == 0x3f30945640000000
double f = a/b;//3015/0.00025298219406977296;
计算(即 “F”)的结果是11917835.000000000(((无符号__int64 )(&F))== 0x4166bb4160000000)尽管它应该是11917834.814763514(即((无符号__int64 )(&F))== 0x4166bb415a128aef)。结果 即小数部分丢失。结果 不幸的是,我需要小数部分是正确的。
问题:结果 1)为什么会发生这种情况?结果 2)如何解决这个问题?
附加信息:搜索 0)的结果被取直接从“表”窗口(这是不打印,我没有忘记设置打印精度)。我还提供了十六进制转储浮点变量的,所以我绝对清楚的计算结果。结果 1)拆卸的F = A / B是:
fld qword ptr [a]
fdiv qword ptr [b]
fstp qword ptr [f]
2)F = 3015 / 0.00025298219406977296;产率正确的结果(F == 11917834.814763514,((无符号__int64 )(&F))== 0x4166bb415a128aef),但它看起来像在这种情况下结果在编译时被简单地计算:
fld qword ptr [__real@4166bb415a128aef (828EA0h)]
fstp qword ptr [f]
那么,如何才能解决这个问题呢?
P.S。我找到了一个临时的解决方法(我只需要分割的小数部分,所以我只是使用f = FMOD(A / B)的时刻/ B),但我还是想知道如何正确地解决这个问题 - 双精度被认为是16个十进制数字,所以这样的计算是不应该引起问题。
解决方案
您在你的程序的任何地方使用的DirectX作为使浮点单元即可切换为单精度模式,除非你明确告诉它不是在创建设备,并会造成正是这种
其他提示
有趣的是,如果你声明A和B作为花车,你会得到完全11917835.000000000。所以我的猜测是,有一个转换为单精度发生什么地方,无论是在怎样的常量解释或稍后在计算中。
这两种情况是有点出人意料,不过,考虑到你的代码是多么简单。您没有使用任何异国情调的编译器指令,迫使单精度所有浮点数字?
编辑:你有没有实际确认编译的程序产生不正确的结果?否则,对于(错误)单精度转换最可能的候选。将调试器。
如果你需要精确的数学,不使用浮动点。的
请你帮个忙,并获得BIGNUM库有理数的支持。
我猜你打印出来的数字,没有指定的精度。尝试这样:
#include <iostream>
#include <iomanip>
int main() {
double a = 3015.0;
double b = 0.00025298219406977296;
double f = a/b;
std::cout << std::fixed << std::setprecision(15) << f << std::endl;
return 0;
}
此产生:
11917834.814763514000000
这看起来是正确的给我。我使用VC ++ 2008,而不是2005年,但我猜想不同的是在你的代码,而不是编译器。
您确定您的FSTP指令后检查F的权值?如果你有开启或者监视窗口可以显示在以后的某个点取一个值优化(这似乎有点似是而非,你说你以后看f的小数部分 - 做一些指令风力可达掩盖它出某种方式?)