可以使用fp:fast 3000.f/1000.f!= 3.f可以吗?
我正在使用MSVC 2019 v16.11.12。
当我尝试用/fp:fast 而不是/fp:精确来编译代码时,我的测试开始失败。
The simplest case is:
BOOST_AUTO_TEST_CASE(test_division) {
float v = 3000.f;
BOOST_TEST((v / 1000.f) == 3.f);
}
Failing with result:
错误:在“ test_division”中:check(v / v / 1000.f)== 3.f失败[3.00000024!= 3] < / p>
I understand that /fp:fast can have worse floating-point precision in有些情况; but, here, it seems excessive...
How come it can't accurately divide 3000 by 1000?
我知道0.1 + 0.2不是0.3,但是在这里所有数字都是可表示的,并且分区恰好返回3, fp:精确。
我有可能还有其他一些旗帜,从而降低了浮点精度?
I'm using MSVC 2019 v16.11.12.
When I tried compiling my code with /fp:fast instead of /fp:precise, my tests started failing.
The simplest case is:
BOOST_AUTO_TEST_CASE(test_division) {
float v = 3000.f;
BOOST_TEST((v / 1000.f) == 3.f);
}
Failing with result:
error: in "test_division": check (v / 1000.f) == 3.f has failed [3.00000024 != 3]
I understand that /fp:fast can have worse floating-point precision in some cases; but, here, it seems excessive...
How come it can't accurately divide 3000 by 1000?
I understand that 0.1 + 0.2 is not 0.3, but here all the numbers are representable and the division returns exactly 3 with fp:precise.
Is it possible that I have some other flag flipped which decreased the floating-point precision even more?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
GCC的-FFAST -MATH选项启用的优化之一(以及MSVC的 /FP:FAST选项)是将“按常数进行划分”转换为“乘以相互乘”,因为浮点数很慢 - 在某些机器超过10倍,就像倍数一样昂贵,因为乘数通常是管道的,而分隔线则不太常见。
这样,
/1000.f
将变成某种精度的* .001
,并且.001不能在浮点上完全表示,因此会发生一些不精确。更确切地说,最接近的32位FP值为.001是0x1.0624DEP-100,而最接近的64位FP为0x1.0624DD2F1A9FCP-10。如果将32位值乘以3000,您将获得0x1.80000132p+1或约3.0000001425。如果将其围成32位,则将获得0x1.800002p+1或约3.0000002384。有趣的是,如果您使用64位值并乘以3000,则将获得0x1.8000000000024p+1,当舍入到64位时,这是确切的0x1.8p+1值。
One of the optimizations which is enabled by gcc's -ffast-math option (and probably msvc's /fp:fast option) is converting a "divide by constant" into a "multiply by reciprocal", as floating point divides are quite slow -- on some machines more than 10x as expensive as a multiply, as multipliers are commonly pipelined while dividers are less commonly pipelined.
With this, the
/ 1000.f
would get turned into a* .001
of some precision, and .001 cannot be exactly represented in floating point, so some imprecision will occur.More precisely, the closest 32-bit FP value to .001 is 0x1.0624dep-10, while the closest 64-bit FP is 0x1.0624dd2f1a9fcp-10. If that 32-bit value is multiplied by 3000 you'll get 0x1.80000132p+1 or about 3.0000001425. If you round that to 32 bits, you'll get 0x1.800002p+1 or about 3.0000002384. Interestingly, if you use the 64-bit value and multiply by 3000, you'll get 0x1.800000000000024p+1, which when rounded to 64 bits is the exact 0x1.8p+1 value.