【问题标题】:loss of precision during widening conversions扩大转换期间的精度损失
【发布时间】:2013-07-14 03:05:11
【问题描述】:

下面代码的输出是

package com.ajay.compoitepattern;
class Test {
        public static void main(String[] args) {
                int big = 1234567890;
                float approx = big;
                System.out.println(big - (approx));
                System.out.println(big - (int)(approx));
        }
}

这个程序的输出是

0.0
-46

我的问题是,如果在扩大转换中丢失了精度,那么第一次应该是 -46 sysout 也是,为什么第一个输出是 0.0 ?

【问题讨论】:

    标签: java types type-conversion


    【解决方案1】:

    第一个输出是 0.0,因为 float 从 int 中减去,它将整个语句放入 float。

    这意味着 int big 也转换为浮点值。基本上你正在做的是(大约 - 大约)(float)big = approx. 这应该是你得到零的原因。

    如果你也想试试这个

    System.out.println(big/(approx));
    

    intfloat 之间的操作将整个语句转换为 float

    【讨论】:

      【解决方案2】:

      这已被 JLS §4.2.4:

      如果二元运算符的至少一个操作数是 浮点型,则运算为浮点运算, 即使另一个是不可分割的。

      在您的第一个示例中,big - approx,因为approxfloat,所以这算作浮点运算。 big 扩展为 float,并且由于 approx 也是 big 扩展为 float,因此精度损失会自行抵消,从而使您的答案为零。

      在您的第二个示例big - (int) approx 中,两个操作数都不是浮点类型,因为您将approx 转换为int。现在存在精度损失,您的答案不再为零。

      【讨论】:

        【解决方案3】:

        Java 中的float 使用 23 位作为尾数,加上 1 个隐含位,因此有 24 个有效位可用,int 由 32 位表示。因此,对于高于 2^23 的 int 值,不可避免地会损失精度。你应该在这里使用double,因为它有53个有效位,所以在第二种情况下结果将为0。

        public static void main(String[] args) {
            int big = 1234567890;
            double approx = big;
            System.out.println(big - (approx)); // --> 0.0
            System.out.println(big - (int) (approx)); // --> 0
        }
        

        【讨论】:

        • 虽然存储了 23 位,但对于规范化的数字,包括从 int 到 float 的所有转换,还有一个额外的隐式位。实际上有 24 个有效位。类似地,双精度数有 53 个有效位。
        • 谢谢德米特里,帕特里夏
        【解决方案4】:

        阅读this可以帮助你理解。也阅读this SO 帖子..

        让我们考虑一下您的代码

            int big = 1234567890;     // here your int big=1234567890;
            float approx = big;
            BigDecimal bd=BigDecimal.valueOf(approx);
            System.out.println(bd);  // Now you can see int to float creates approx= 1234567936;
            System.out.println(big - (approx));     // In here big again casting to float since you are doing a operation with float, result is zero.
            System.out.println(big - (int)(approx)); // here big=1234567890 and approx= 1234567936. so difference is -46
        

        【讨论】:

        • 仅链接的答案是frowned upon
        • @Jeffrey 你现在可以查看我的答案
        猜你喜欢
        • 2019-03-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-11-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多