我正在重新讨论一个问题(如何测试数字转换是否会改变值?),就我而言,它已经完全解决了。问题是检测特定数值何时会溢出 JavaScript 的 IEEE-754 数字类型。上一个问题是使用 C# 并且标记的答案非常有效。
现在我正在做完全相同的任务,但这次是在 Java 中,它不起作用。AFAIK,Java 使用 IEEE-754 作为其double
数据类型。所以我应该能够来回投射它以强制损失精度,但它是往返的。对此感到困惑的是,我开始深入研究 Java,现在我真的很困惑。
在 C# 和 Java 中,long 的最小值和最大值是相同的:
long MIN_VALUE = -9223372036854775808L;
long MAX_VALUE = 9223372036854775807L;
AFAIK,这些值超出了 IEEE-754 中可表示的数字,因为为指数和符号保留了固定位。
// this fails in browsers that have stuck with the pure ECMAScript Number format
var str = Number(-9223372036854775808).toFixed();
if ("-9223372036854775808" !== str) { throw new Error("Overflow!"); }
这false
在 Java 中返回 (value = -9223372036854775808L):
boolean invalidIEEE754(long value) {
try {
return ((long)((double)value)) != value;
} catch (Exception ex) {
return true;
}
}
这false
在 Java 中返回 (value = -9223372036854775808L):
boolean invalidIEEE754(long value) {
// trying to get closer to the actual representation and
// being more explicit about conversions
long bits = Double.doubleToLongBits(Long.valueOf(value).doubleValue());
long roundtrip = Double.valueOf(Double.longBitsToDouble(bits)).longValue();
return (value != roundtrip);
}
这返回true
(value = -9223372036854775808L) 但不太准确:
boolean invalidIEEE754(long value) {
return (0x0L != (0xFFF0000000000000L & (value < 0L ? -value : value)));
}
为什么会这样?我是否缺少诸如编译器优化之类的东西,例如编译器是否检测到我的转换并为我“修复”它们?
编辑:按要求添加测试用例。所有这三个测试都失败了:
import static org.junit.Assert.*;
import org.junit.Test;
public class FooTests {
@Test
public void ieee754One() {
assertTrue(((long)((double)Long.MIN_VALUE)) != Long.MIN_VALUE);
}
@Test
public void ieee754Two() {
long bits = Double.doubleToLongBits(Long.valueOf(Long.MIN_VALUE).doubleValue());
long roundtrip = Double.valueOf(Double.longBitsToDouble(bits)).longValue();
assertTrue(Long.MIN_VALUE != roundtrip);
}
@Test
public void ieee754Three() {
long bits = Double.doubleToRawLongBits(Long.valueOf(Long.MIN_VALUE).doubleValue());
long roundtrip = Double.valueOf(Double.longBitsToDouble(bits)).longValue();
assertTrue(Long.MIN_VALUE != roundtrip);
}
}