(x/y >= z)什么时候用浮点数表示(x >= y*z)?

问题描述 投票:0回答:1

我知道浮点数并不是实数的精确表示,并且有各种“模糊比较”方法可以避免实践中出现意外。 这个问题讨论了平等的保证,但就我而言,我想知道是否有推荐的方法来确保乘法保留顺序。

这是我最近遇到的一个问题:

#include <cstdint>
#include <iostream>

int main() {
    // convert hex to float
    uint32_t ux = 0x3f666666;
    uint32_t uy = 0x3dcccccd;

    float x = *((float*) &ux);
    float y = *((float*) &uy);

    // floor the quotient
    float z = std::floor( x / y );
    printf("%.12f\n",x);
    printf("%.12f\n",y);
    std::cout << std::boolalpha << (x/y >= z) << std::endl;
    std::cout << std::boolalpha << (x >= z*y) << std::endl;
}

输出:

0.899999976158
0.100000001490
true
false

事实上 floor 没有给出准确的结果 并不是问题所在。我的问题是关于如何保留顺序。具体来说,在上面的示例中,我们有

x/y >= z
但没有
x >= y*z
,并且所涉及的数字都不接近该类型可以表示的最小/最大值。

是否存在我们知道其中一个暗示另一个的情况(例如所涉及数字的条件)?或者是否有不同的(非平凡的)方式或编写一种暗示另一种的方式?例如,也许

x*y/y > y*z
总是意味着
x/y > z
(即使反之亦然)?

c++ floating-point
1个回答
-2
投票

可以通过在比较中将精度扩展到双精度来实现浮点数。

其中 x、y 和 z 为浮点数,将

x/y >= z
x >= y*z
更改为
1.0*x/y >= 1.0*z
1.0*x >= 1.0*y*z

关于您提到的其他几点:

您可以使用

std::bit_cast
轻松地将十六进制表示转换为浮点数。反过来也同样容易。

#include <cstdint>
#include <bit>
#include <iostream>

int main()
{
    uint32_t sx = 0x3f666666;
    uint32_t sy = 0x3dcccccd;
    float sxf = std::bit_cast<float>(sx);
    float syf = std::bit_cast<float>(sy);
    std::cout << sxf << '\n' << syf << '\n';    // outputs .9 and .1
}

对于浮点数,该技术保留足够的精度以提供一致的结果。将比较的变量转换为双精度。

std::cout << std::boolalpha << (1.0*x / y >= 1.0*z) << std::endl;
std::cout << std::boolalpha << (1.0*x >= 1.0*z * y) << std::endl;

通过在乘法/除法之前将浮点数转换为双精度数,可以保持足够的精度,假设 x、y 和 z 是浮点数且浮点数/双精度数是标准 IEEE 大小,则

x/y >= z
x >= y*z
将匹配。

© www.soinside.com 2019 - 2024. All rights reserved.