为什么numeric_limitsMachineEpsilon不满足1+e>1条件?

如果我没记错的话,Machine Epsilon 的定义是满足条件的最低数字:

我试图使用 来测试这个,std::numeric_limits<float>::epsilon()但如果您尝试使用以下方法获取先前的浮点数,则该值不满足此要求std::nextafter

#include <cmath>
#include <iostream>
#include <limits>

int main() {
    float e = std::numeric_limits<float>::epsilon();
    float previous = std::nextafter(e, -std::numeric_limits<float>::infinity());

    std::cout << std::boolalpha << ((1.0f + previous) > 1.0f) << std::endl;

    return 0;
}

This stills outputs true https://coliru.stacked-crooked.com/a/841e19dafcf0bf6f.

After trying to get the number using std::nextafter I noticed that the proper Machine Epsilon should be:

std::nextafter(std::numeric_limits<float>::epsilon() / 2.0f, std::numeric_limits<float>::infinity())

I tested it using this code:

#include <cmath>
#include <iostream>
#include <limits>

bool verify(float e) {
    return ((1.0f + e) > 1.0f);
}

int main() {
    std::cout.precision(std::numeric_limits<float>::digits);
    std::cout << std::boolalpha << std::fixed;

    float epsilon = std::numeric_limits<float>::epsilon();

    float last = epsilon;
    while (true) {
        last = std::nextafter(last, -std::numeric_limits<float>::infinity());
        if ((1.0f + last) > 1.0f) {
            epsilon = last;
        } else {
            break;
        }
    }

    // Does not satisfy condition
    std::cout << "last: " << verify(last) << " " << last << std::endl;
    // Satisfy condition
    std::cout << "epsilon: " << verify(epsilon) << " " << epsilon << std::endl;

    float half_epsilon = std::numeric_limits<float>::epsilon() / 2.0f;
    float actual_epsilon = std::nextafter(half_epsilon, std::numeric_limits<float>::infinity());
    // Same as 'last' at this point
    std::cout << "half_epsilon: " << verify(half_epsilon) << " " << half_epsilon << std::endl;
    // Same as 'epsilon' at this point
    std::cout << "actual_epsilon: " << verify(actual_epsilon) << " " << actual_epsilon << std::endl;

    return 0;
}

This outputs

last: false 0.000000059604644775390625
epsilon: true 0.000000059604651880817983
half_epsilon: false 0.000000059604644775390625
actual_epsilon: true 0.000000059604651880817983

https://coliru.stacked-crooked.com/a/3c66a2144e80a91b

Am I missing somethig here?

回答

如果我没记错的话,Machine Epsilon 的定义是满足条件的最低数字:[ 1 + epsilon > 1]

关闭,但您在 C++ 的上下文中是错误的。(我相信你的定义在其他更学术的环境中是正确的。)根据cppreference.com,机器 epsilon 是“ 1.0[指定]浮点类型可表示的下一个值之间的差异”。机器 epsilon 确实满足1 + epsilon > 1,但不必是满足该条件的最低数。但是,它是在所有舍入模式下满足该条件的最低数字。

因为机器 epsilon 比 小得多1.0,所以 epsilon 和 之间有很多可表示的值0.0。(这是浮点表示的一个基本目标。)当这些中的任何一个被添加到 时1.0,结果是不可表示的,所以结果需要四舍五入。如果舍入模式是最接近的可表示值,那么1 + epsilon只要小数在epsilon/2和之间,该总和就会舍入到3*epsilon/2。另一方面,如果舍入模式始终趋向于零,那么您会得到预期的结果。

尝试将以#include <cfenv>下行添加到您的代码中。

fesetround(FE_TOWARDZERO);

这会导致严格介于1.0和之间的任何总和1 + epsilon四舍五入到1.0。您现在应该会看到机器 epsilon 的行为与您预期的一样。

其他有保证的舍入模式是朝向 -infinity 和朝向 +infinity。有关详细信息,请参阅cppreference.com。


以上是为什么numeric_limitsMachineEpsilon不满足1+e&gt;1条件?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>