【发布时间】:2015-08-11 18:24:29
【问题描述】:
所以我已经阅读了很多这方面的内容,所以请知道我知道像 0.6 这样的数字不能绝对准确地表示为 Java 双精度 - 但我知道有一个双精度版本代表数字 0.6 足够接近,以至于数字显示为 0.6 而不是像 0.6000000000000001 在该数字的大多数最终解释中(例如,包括 toString() 或使用像杰克逊这样的库封送到 JSON - 我的目标)。
我正在寻找一种将双精度数强制转换为被解释为相对截断精度的数字的机制。例如,如果我想截断到 0.1 精度,我想要将 0.6975265613 截断到 0.1 精度的东西为 0.6,而不是 0.6000000000000001
所以,基本上使以下测试工作:
@Test
public void testRounding() {
// prove there is a value that displays cleanly
Double cleanValue = 0.6d;
assertEquals("0.6", cleanValue.toString());
Double value = 0.6975265613d;
Double precision = 0.1d;
value = value / precision;
value = value.longValue() * precision;
// this fails with 0.6000000000000001
assertEquals("0.6", value.toString());
}
我使用 longValue() 来截断速度,但使用 Math.floor() 会得到相同的结果。
查看原始双十六进制值,上面的 cleanValue 是: 3fe3333333333333
而四舍五入的结果(值)为: 3fe3333333333334
我需要一种能够始终如一地为我提供预期版本(第一个)的技术,而不管舍入精度如何 - 假设精度不会突破类型的精度限制。转换为 String 或 BigDecimal 会太慢 - 这是一个分析应用程序,其中这些方法的 x10 成本非常可衡量。
再次,理解这两个十六进制数字都不是真正代表 实际 数字 0.6,我只是想让 Java 认为它是 0.6(即 3fe3333333333333):)
谢谢!
【问题讨论】:
-
所以你要做的是找到整数
x和y使得x / 10^y尽可能接近双倍。所以这是一个二维优化问题。 -
有什么理由不想使用 BigDecimal?
-
我建议不要将精度存储为
0.1d- 您在那里遇到了一个很容易避免的舍入误差。 -
我认为这没有任何实际意义。有太多方法可以将双精度转换为十进制,以使单一技术在双端可靠。您应该关注的是转换过程本身,它易于控制,并确保您始终使用它。
-
我不知道,对我来说似乎足够实用。我们要求
+和/这样的运算正确舍入;为什么不要求同样的舍入?这不像exp,在一个 ULP 内有一个令人信服的理由来满足准确性。
标签: java rounding precision point floating