【问题标题】:Does a value x of type float exist for which x + 1 == x?是否存在 x + 1 == x 的 float 类型的值 x?
【发布时间】:2019-12-04 20:23:18
【问题描述】:

这是考试中的一道题,但没有明确解释原因。 这是一个真/假类型的问题;

存在一个 float 类型的值 x 持有:x + 1 == x...

这是真的。为什么?

我猜这与类型转换有关?但我无法想象这将如何运作。

【问题讨论】:

标签: c++ floating-point type-conversion


【解决方案1】:

当然。

#include <limits>
#include <iostream>
int main() {
    float f = std::numeric_limits<float>::infinity();
    std::cout << (f == f + 1) << std::endl;
}

正如 Deduplicator 指出的那样,如果您的 float 足够大(适用于我的 float f = 1e20;),它也会起作用,因为添加的 1 将超出 float 的准确性。

Try it online

【讨论】:

  • 不需要去无穷大,1 在很久以前就显得微不足道了。虽然不可否认,一路走来更简单。
  • @Deduplicator 感谢您指出这一点,我忘记了这一点。添加它来回答。我认为这可能是 OP 考试正在寻找的实际答案,因为它证明了浮点数的局限性。
  • 并非所有浮点表示都支持无穷大。在 C++11 中,x 的值 std::nextafter(x) - x &gt; 2.0 可能还会给出 x 的值,x == x + 1 的值将测试为 true。
【解决方案2】:

这段代码编译没有错误:

#include <limits>

int main()
{
    static_assert(std::numeric_limits<float>::infinity() == std::numeric_limits<float>::infinity() + 1.0f, "error");
    static_assert(std::numeric_limits<double>::infinity() == std::numeric_limits<double>::infinity() + 1.0, "error");
    return 0;
}

online version


您甚至不需要使用无穷大。如果数字足够大,则舍入误差会变得足够大,因此将数字加一根本不会改变它。 例如

static_assert(100000000000000000000000.f == 100000000000000000000000.f + 1.0, "error");

不过,您必须在此处输入的0 的具体数量可能是实现定义的。

在编写使用浮点数的程序时,请始终牢记四舍五入。

【讨论】:

    【解决方案3】:
    #include <iostream>
    
    int main()
    {
        float val = 1e5;
        while (val != val + 1)
            val++;
        std::cout << val << "\n";
        return 1;
    }
    

    clang 打印1.67772e+07

    存在一个浮点类型的值 x 持有:x + 1 == x... 这是真的。为什么?

    原因在于how floating point numbers work。基本上 32 位浮点数有 24 位用于尾数(基数)和 8 位用于指数。在某些时候 +1 不会导致二进制表示发生变化,因为指数太高了。

    【讨论】:

    • 是的,2^24 = 16777216 和 16777217 不能用 IEEE754 32 位浮点数精确表示:float(16777217) == 16777216.0。之后的每个奇数也是如此。
    【解决方案4】:

    对于 32 位 IEEE754 浮点数(也称为单精度或 SP),最小非负正常值是 16777216。即16777216 + 1 == 16777216

    数字16777216 正好是2^24。 SP 浮点数有 23 位尾数。这是它在内部的表示方式:

                      3  2          1         0
                      1 09876543 21098765432109876543210
                      S ---E8--- ----------F23----------
              Binary: 0 10010111 00000000000000000000000
                 Hex: 4B80 0000
           Precision: SP
                Sign: Positive
            Exponent: 24 (Stored: 151, Bias: 127)
           Hex-float: +0x1p24
               Value: +1.6777216e7 (NORMAL)
    

    你可以看到整个尾数是 0。如果你在这个数字上加 1,它会击中间隙并被吸收,让你回到你开始的状态。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-08-09
      • 2011-11-20
      • 1970-01-01
      • 2011-02-10
      • 2013-01-09
      • 2022-12-14
      • 2021-06-30
      相关资源
      最近更新 更多