我正在编写一个程序,从数据库获取原始 double 值并将其转换为 8 字节十六进制字符串,但我不知道如何防止精度损失。从所有设备接收到的数据都存储为 double ,包括 8 字节标识值。
double 实例(例如 7.2340172821234e+16)可以正确解析,且不会损失精度,其中指数为 10^16。
但是,在指数为 10^17 的情况下,Java 会丢失精度。 例如,2.88512954935019e+17被Java解释为1.44464854248327008E17
我使用的代码如下所示:
public Foo(double bar) {
this.barString = Long.toHexString((long) bar);
if (barString.length == 15) {
barString = "0" + barString; //to account for leading zeroes lost on data entry
}
}
我正在使用与此类似的测试用例来测试它:
@Test
public void testFooConstructor() {
OtherClass other = new OtherClass();
OtherClass.Foo test0 = other.new Foo(72340172821234000d); //7.2340172821234e+16
assertEquals("0101010100000150", test0.barString); //This test passes
OtherClass.Foo test1 = other.new Foo(144464854248327000d);//1.44464854248327e+17
assertEquals("02013e0500000758, test1.barString); //This test fails
}
单元测试指出:
Expected: 02013e0500000758
Actual: 02013e0500000760
当我打印出 Java 存储的值 72340172821234000d 和 144464854248327000d 时,它们分别打印:
7.2340172821234E16
1.44464854248327008E17
后一个值相差 8,这对于我测试过的少数几个来说似乎是一致的。
我可以做些什么来纠正这个错误吗?
编辑:这不是我关心超出该位置的内容的问题。有些人认为这是重复的问题是问为什么 float 不太精确,我问如何通过与 Roman Puchkovskiy 类似的解决方法来避免精度损失。建议。
最佳答案
您可以将数据库中的浮点值作为字符串(而不是浮点),然后使用 BigDecimal
将它们转换为 long
:
String fpAsString = getFromDB();
long longValue = new BigDecimal(fpAsString).longValue();
this.barString = Long.toHexString(longValue);
BigDecimal
.longValue() 类似于从 double
到 long
的缩小原始转换,但它不会丢失精度(除了丢失小数部分)。如果结果不适合 long
,您可能会丢失一些东西,但转换为 long
也会发生同样的情况。
关于java - 如何避免 Java 中 double 造成的精度损失?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45492624/