可以使用fp:fast 3000.f/1000.f!= 3.f可以吗?

发布于 2025-01-21 16:15:57 字数 709 浏览 1 评论 0原文

我正在使用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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

七分※倦醒 2025-01-28 16:15:57

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文