繁体   English   中英

长值如何适合 Java 中的浮点数据类型而不会损失精度

[英]How does long value fit in float data type in Java without loss of precision

长值如何适合 Java 中的浮点数据类型而不会损失精度。 因为如果精度损失那么下面的代码片段应该产生

long lMax = Long.MAX_VALUE;
float f = lMax;
System.out.println(lMax == f);

Output 
true

问题是,为了比较longfloatlong值被转换为float ,并且发生了与赋值相同的精度损失......

如果您想“检测”精度损失,请尝试使用BigDecimal s,如下所示:

System.out.println(new BigDecimal(lMax).compareTo(new Bigdecimal(f)));

我知道构造函数BigDecimal(double)会将floatdouble精度,但没有精度丢失...

编辑

对于大多数人来说, long似乎比float更“精确”。 但是float的范围是+/-10^38 ,这比long的大得多......

测试

long lMax = Long.MAX_VALUE;
float f = lMax;
System.out.println( lMax == f );
System.out.println( new BigDecimal( lMax ).compareTo( new BigDecimal( f ) ) );
System.out.println( ( (Float) f ).longValue() == lMax );
System.out.println( ( (Long) lMax ).floatValue() == f );
System.out.printf( "%d, %d%n", ( (Float) f ).longValue(), lMax );

f = --lMax;
System.out.println( lMax == f );
System.out.println( new BigDecimal( lMax ).compareTo( new BigDecimal( f ) ) );
System.out.println( ( (Float) f ).longValue() == lMax );
System.out.println( ( (Long) lMax ).floatValue() == f );
System.out.printf( "%d, %d%n", ( (Float) f ).longValue(), lMax );

输出:

true
-1
true
true
9223372036854775807, 9223372036854775807
true
-1
false
true
9223372036854775807, 9223372036854775806

Java 语言规范中的二进制数字提升规则是理解问题中代码片段行为的关键。 特别是“否则,如果任一操作数的类型为 float,则另一个将转换为 float”。

lMax == f比较中, lMax 完全转换为 float ,正如float f = lMax赋值所做的float f = lMax 如果取相同的输入值,对其进行两次相同的转换,然后比较结果,无论转换是否改变了值,它们都将相等。

如果您想很好地演示精度损失,请在以毫秒为单位获取系统时间并从 long 转换为 float 时尝试这个小脚本:

class Scratch {
    public static void main(String[] args) throws InterruptedException {

        float currentF;
        long currentL;
        float lastNewF = 0;
        long lastL = System.currentTimeMillis();
        long diff;

        while (true) {
            currentL = System.currentTimeMillis();
            currentF = (float) currentL;
            if (currentF != lastNewF) {
                // we finally got a new "different" float value
                lastNewF = currentF;
                diff = currentL - lastL;
                lastL = currentL;
                System.out.println(diff + " milliseconds since we got a new time as float");
            }
            Thread.sleep(250);
        }
    }
}

您可以从输出中看到有时会丢失多达 2 分钟的精度:

0 milliseconds since we got a new time as float
46964 milliseconds since we got a new time as float
131054 milliseconds since we got a new time as float
131093 milliseconds since we got a new time as float
131077 milliseconds since we got a new time as float

lMax的值=9223372036854775807; // 在您的 JVM 中可能会有所不同。

f 的值 = 9.223372E18

现在,当您比较lMax == f ,首先将 f 转换为 long,然后进行比较。 转换成long后,f值与lMax相同。

甚至同样适用于以下代码。

long lMax = Long.MAX_VALUE; // value is 9223372036854775807
float f =lMax;
float f2 = 9223372036854775807.5f;
System.out.println(lMax == f);
System.out.println(lMax == f2);

输出

true
true

与 long 相比,这里 f2 正在丢失十进制值。 f2 的 long 值与 lMax 相同。

lMax 是一个长数。 当你将它分配给一个浮点数时,它会失去精度。

浮动 f = lMax;

当您将 long 与 float 进行比较时,在内部将 long 转换为 float 或将 float 转换为 long。 你的代码

lMax == f

将类似于

((Float)f).longValue() == lMax

这是 9.223372E18 == 9.223372E18 真

((Long)lMax).floatValue() == f

这是 9223372036854775807 == 9223372036854775807 true

无论哪种方式,答案都是正确的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM