long值如何适合Java中的float数据类型而又不损失精度

问题描述 投票:2回答:5

长值如何适合Java中的float数据类型而又不损失精度。因为如果丢失精度,则应该生成以下代码段

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

Output 
true
java floating-point precision long-integer
5个回答
3
投票

问题是,为了比较longfloatlong值被强制转换为float,并且与分配中一样发生了精度损失。

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

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

我知道构造函数BigDecimal(double)将把float强制转换为double,但没有精度损失...

编辑

[对大多数人而言,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

0
投票

Java语言规范中的Binary Numeric Promotion规则是理解问题中代码片段行为的关键。特别是“否则,如果其中一个操作数的类型为float,则另一个将转换为float。”

lMax == f比较中,与float f = lMax赋值完全一样,将lMax转换为浮点数。如果采用相同的输入值,则对它进行两次相同的转换,然后比较结果,它们将相等,而不管转换是否更改了该值。


0
投票

如果要很好地演示精度损失,请在获取系统时间(以毫秒为单位并从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

-1
投票

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

float 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

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


-1
投票

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

与长整数相比,f2在此丢失十进制值。 f2的长值与lMax相同。

© www.soinside.com 2019 - 2024. All rights reserved.