长值如何适合Java中的float数据类型而又不损失精度。因为如果丢失精度,则应该生成以下代码段
long lMax = Long.MAX_VALUE;
float f = lMax;
System.out.println(lMax == f);
Output
true
问题是,为了比较long
和float
,long
值被强制转换为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
Java语言规范中的Binary Numeric Promotion规则是理解问题中代码片段行为的关键。特别是“否则,如果其中一个操作数的类型为float,则另一个将转换为float。”
在lMax == f
比较中,与float f = lMax
赋值完全一样,将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是一个长数字。当您将其分配给浮点数时,它将失去精度。
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
无论哪种方式,答案都是正确的。
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相同。