简体   繁体   English

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

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

How does long value fit in float data type in Java without loss of precision.长值如何适合 Java 中的浮点数据类型而不会损失精度。 Because if there is loss of precision then the following snippet should have produced因为如果精度损失那么下面的代码片段应该产生

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

Output 
true

The problem is, that for comparison of long and float the long value is being cast to float , and the same loss of precision occurred as in the assignment...问题是,为了比较longfloatlong值被转换为float ,并且发生了与赋值相同的精度损失......

If you want to "detect" loss of precision, try using BigDecimal s, something like this:如果您想“检测”精度损失,请尝试使用BigDecimal s,如下所示:

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

I know that the constructor BigDecimal(double) will get the float cast to double but there is no precision lost...我知道构造函数BigDecimal(double)会将floatdouble精度,但没有精度丢失...

Edit编辑

For most people long seems to have more "precision" than float .对于大多数人来说, long似乎比float更“精确”。 However float has a range of +/-10^38 , which is much larger than long 's...但是float的范围是+/-10^38 ,这比long的大得多......

Tests测试

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 );

Outputs:输出:

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

The Binary Numeric Promotion rules in the Java language Specification are key to understanding the behavior of the code snippet in the question. Java 语言规范中的二进制数字提升规则是理解问题中代码片段行为的关键。 In particular "Otherwise, if either operand is of type float, the other is converted to float."特别是“否则,如果任一操作数的类型为 float,则另一个将转换为 float”。

In the lMax == f comparison, lMax is converted to float exactly as was done by the float f = lMax assignment.lMax == f比较中, lMax 完全转换为 float ,正如float f = lMax赋值所做的float f = lMax If you take the same input value, do the same transformation on it twice, and compare the results they will be equal regardless of whether the transformation changed the value or not.如果取相同的输入值,对其进行两次相同的转换,然后比较结果,无论转换是否改变了值,它们都将相等。

If you want a good demonstration of the precision loss, try this little script when getting system time in milliseconds and converting from long to float:如果您想很好地演示精度损失,请在以毫秒为单位获取系统时间并从 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);
        }
    }
}

You can see from the output that you are sometimes losing up to 2 minutes of precision:您可以从输出中看到有时会丢失多达 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

The value of lMax =9223372036854775807; lMax的值=9223372036854775807; // It might be different in your JVM. // 在您的 JVM 中可能会有所不同。

Value of f = 9.223372E18 f 的值 = 9.223372E18

Now when you compare lMax == f , first f is converted to long and then comparison happens.现在,当您比较lMax == f ,首先将 f 转换为 long,然后进行比较。 After converting into long, f value is same as lMax.转换成long后,f值与lMax相同。

Even same apply for following code.甚至同样适用于以下代码。

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);

Output输出

true
true

Here f2 is losing decimal value when compared to long.与 long 相比,这里 f2 正在丢失十进制值。 And long value of f2 is same as lMax. f2 的 long 值与 lMax 相同。

lMax is a long number. lMax 是一个长数。 When u assign it to a float it will lose the precision.当你将它分配给一个浮点数时,它会失去精度。

float f = lMax;浮动 f = lMax;

When you compare a long to a float, internally either long is converted to a float or float is converted to a long.当您将 long 与 float 进行比较时,在内部将 long 转换为 float 或将 float 转换为 long。 your code你的代码

lMax == f lMax == f

will be similar to将类似于

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

which is 9.223372E18 == 9.223372E18 true这是 9.223372E18 == 9.223372E18 真

or

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

which is 9223372036854775807 == 9223372036854775807 true这是 9223372036854775807 == 9223372036854775807 true

in either way the answer is true.无论哪种方式,答案都是正确的。

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

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