首页 > 解决方案 > BigDecimal 到 Double 以添加到 JSON 对象

问题描述

我们如何在 Kotlin 中将 BigDecimal 转换为 Double 而不会丢失精度?我需要把它放在一个 JSON 响应中。

我正在使用 Vert.x 和 JsonObject。我尝试将具有刻度 2 的 BigDecimal 转换为具有toDouble. 在内部它使用杰克逊作为对象映射器

例子:

目前:
BigDecimal("0.000")-> 回应:{ amount: 0.0 }

我需要什么:
BigDecimal("0.000")-> 响应:{ amount: 0.000 }

标签: jsonkotlinjacksondoublebigdecimal

解决方案


恐怕您无法将 BigDecimal 转换为 Double 而不会丢失精度,原因如下:

  • BigDecimal 的可能值比 Double 多得多,因此转换必然是有损的。

双精度数是 64 位的,因此不能有超过 2⁶⁴ 的不同值,而 BigDecimals 实际上是无限的。

  • BigDecimals 存储十进制分数,而 Doubles 存储二进制分数。两者之间几乎没有重叠,因此在大多数情况下,转换需要对值进行四舍五入。

两者都可以精确存储整数(直到某个值),并且都可以精确存储诸如 0.5 之类的小数。但是几乎所有的十进制分数都不能精确地表示为二进制分数,因此例如没有 Double 正好保持 0.1。(1/10 是二进制的无限循环分数——0.0001100110011…——因此没有有限的二进制分数可以准确地表示它。)

这意味着在 Kotlin(和大多数其他编程语言)中,诸如 0.1 之类的数字文字会被转换为最接近的双精度数,大约为 0.100000000000000005551115……。实际上,这通常对您隐藏,因为当您打印出 Double 时,格式化例程会将其四舍五入,并且在许多情况下会返回原始数字。但并非总是如此,例如:

>>> println(0.1 + 0.1 + 0.1)
0.30000000000000004

(所有这些都在其他问题中讨论,最值得注意的是这里。)

  • 与 BigDecimal 不同,双精度数没有精度,因此无论如何它们都无法做出您想要的区分。

例如,1.0 和 1.000000 都由完全相同的 Double 值表示:

>>> println(1.000000)
1.0

我不知道 Vert.x,但如果你真的需要一个 Double,我会很惊讶。您是否尝试过直接使用 BigDecimal?

或者如果这不起作用,您是否尝试过将其转换为字符串,这将保留您想要的任何格式?


推荐阅读