java - 如何避免 Java 中 double 造成的精度损失?

标签 java precision

我正在编写一个程序,从数据库获取原始 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() 类似于从 doublelong 的缩小原始转换,但它不会丢失精度(除了丢失小数部分)。如果结果不适合 long,您可能会丢失一些东西,但转换为 long 也会发生同样的情况。

关于java - 如何避免 Java 中 double 造成的精度损失?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45492624/

相关文章:

java - SpringBoot上传Excel并读取为JSON

java - 从数据库获取信息

c++ - Hexfloat 机械手和精度

math - float 学坏了吗?

c - 如何在C中自动缩放浮点值?

java - 如何在 gerrit 中安装删除项目插件?

java - 我正在尝试读取文本文件并将其存储在对象的数组列表中

java - Android 媒体播放器通知

c++ - 如何比较精度为 5 位的 double ?

C++ std::nextbefore 函数?