【问题标题】:Precision of multiplication by 1.0 and int to float conversion乘以 1.0 和 int 到浮点转换的精度
【发布时间】:2012-11-04 05:49:52
【问题描述】:

假设条件(int)(i * 1.0f) == i 对任何整数i 为真是否安全?

【问题讨论】:

  • 我想是的,因为任何尾数位都会丢失。不过,我不知道int 是否会晋升为float
  • 出于某种原因,我想说,但我真的没有理由这样做... :-]
  • @John:我也有同样的感觉。我也在考虑大整数,以及乘以1.0 是否有任何保证……不过,在 IEEE754 中,答案可能是“是”。
  • @John:这也是我最初的感觉,现在我完全不知道 :)

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


【解决方案1】:

没有。

如果i 足够大以至于int(float(i)) != i(假设float 是IEEE-754 单精度,i = 0x1000001 足以证明这一点)那么这是错误的,因为乘以1.0f 会强制转换为float ,即使随后的乘法不会改变值。

但是,如果 i 是一个 32 位整数,而 double 是 IEEE-754 双精度,那么 是真的 int(i*1.0) == i


为了完全清楚,乘以1.0f 精确的。可能不是从intfloat 的转换。

【讨论】:

  • 补充这个答案:简单来说,精度损失是由于浮点只有 24 位来容纳 int,而 int 有 32 位,因此最低有效位将是在演员阵容中四舍五入。
  • rounded,不是discarded,但是是的,完全正确。
  • @anatolyg:不。在 C++ 中,这受第 5 节第 10 段的约束(通常的算术转换):“如果任一操作数是浮点数,则应转换另一个操作数漂浮。”所以i在乘法之前被转换为float,这会导致舍入。
  • @MichaelShopsin:a <= ba > b 中的一个为真,除非 ab 是 NaN。
  • @MichaelShopsin:你们都是对的。 Eric 的声明完全适用于标准定义的浮点数。然而,已经有据可查的编译器错误产生了 Michael 所描述的行为。不过需要明确的是,这不是浮点比较的问题。这是错误编译器的问题。
【解决方案2】:

不,IEEE-754 浮点数比整数具有更大的动态范围,但在相同位宽下会牺牲整数精度。

例如看这个小sn-p的输出:

int main() {
        int x = 43046721;

        float y = x;

        printf("%d\n", x);
        printf("%f\n", y);
}

43046721 无法以 32 位 float 数字中可用的 24 位精度正确表示,因此输出如下所示:

43046721
43046720.000000

事实上,我预计任何高于 16,777,216 的奇数在转换为 32 位 float 数字时都会出现同样的问题。

几个兴趣点:

  • 这更多地与隐式 int 到浮点转换有关,而不是与乘法本身有关。

  • 这绝不是 C 独有的 - 例如 Java 也存在完全相同的问题。

  • 大多数编译器都有优化选项,通过忽略标准的某些限制,这些选项可能会影响此类转换的处理方式。在这种情况下,如果编译器优化了与 float 的转换并返回,(int)((float)x * 1.0f) == x 可能始终为 true

【讨论】:

    【解决方案3】:

    不,行为是实现定义的,因为 C 和 C++ 不需要 IEEE-754,尽管这是迄今为止最常见的表示。

    为了确保使用 IEEE-754:

    • 在 C 中,使用 #ifdef __STDC_IEC_559__
    • 在 C++ 中,使用 std::numeric_limits<float>::is_iec559 常量

    【讨论】:

    • 很高兴知道,谢谢!您是否知道任何不符合 IEEE-754 的现代(或当前正在使用的)实现?
    【解决方案4】:

    不,由于类型转换,所有整数都是绝对错误的。检查代码。

    #include <stdio.h>
    
    int main()
    {
        int i = 0;
        for (; i < 2147483647; ++i) {
            if ((int)(i * 1.0f) != i) {
                printf("not equal\n");
                break;
            }
        }
        printf("out of the loop\n");
        getchar();
        return 0;
    }
    

    此代码假定您采用 32 位整数

    【讨论】:

    • 32767 != INT_MAX 用于 32 位整数。
    • 呃,你确实运行了这个程序,对吧?因为它实际上在我的系统上打印“不等于”,因为它应该......
    • @thkala 这里没有打印“不等于”,如果重要的话,我的系统是 32 位的。
    • @user9000:您使用的是什么平台和编译器?
    • @thkala 允许浮点计算以比类型指定的更高的精度和范围执行。因此允许编译器使用doubles 甚至long double 或扩展的80 位x87 浮点数,在这种情况下,不打印“不等于”是合法的。另一种(不太可能)的可能性是float 已经具有至少 31 位的精度。但是对于标准 IEEE754 32 位 floats,如果测试更改为 if ((int)((float)i * 1.0f) != i),它必须打印“不等于”。
    猜你喜欢
    • 1970-01-01
    • 2015-08-30
    • 1970-01-01
    • 1970-01-01
    • 2023-03-31
    • 1970-01-01
    • 2020-02-03
    • 2017-01-19
    • 2016-06-01
    相关资源
    最近更新 更多