在Java中应该如何正确处理BigDecic的转换舍入错误:
BigDecimal -> byte[] -> BigDecimal
我有一个长度为 32 字节的自定义数据类型(是的,32 字节而不是 32 位),我需要将BigDecimal
的小数部分解码为byte[]
.
我知道我会失去一些准确性。是否有任何既定的技术来实现这种转换?
注意: 它是形式MxN
的定点数据类型,其中M % 8 == N % 8 == 0
定点小数部分可以解释为分数n/(2256) 的分子n。 因此,我建议计算表示 1/(2256) 的BigDecimal
值(这完全可以表示为BigDecimal
)并将对它的引用存储在final static
字段中。
要转换为byte[]
,然后,使用BigDecimal.divideToIntegralValue()
的双参数版本将起始数字的小数部分除以 1/(2256),使用MathContext
参数指定所需的舍入模式。 大概你想要RoundingMode.HALF_EVEN
或RoundingMode.HALF_UP
. 然后通过BigDecimal.unscaledValue()
获取结果的BigInteger
未缩放值(在数值上应等于缩放值,因为整数值应具有缩放 0)。 然后,BigInteger.toByteArray()
会给你一个与你所追求的东西密切相关的byte[]
。*
要走另一条路,你几乎可以逆转这个过程。BigDecimal
有一个构造函数,它接受与您的表示非常密切相关的byte[]
。 使用该构造函数,将byte[]
转换为BigInteger
,然后通过适当的构造函数转换为BigDecimal
。 乘以存储的 1/(2256) 值以获得所需的小数部分。
*这里最大的技巧可能涉及适当地摆动标志。 如果您的BigDecimal
可能是负数,那么您可能希望在转换为byte[]
之前先获取它们的绝对值。 更重要的是,BigInteger
产生和消费的byte[]
使用二进制补码表示(即带有符号位),而我想你会想要一个无符号的纯二进制表示。 这主要意味着在转换时需要留出额外的位 - 因此需要整个额外的字节。 还要注意字节顺序;检查BigInteger
的文档以了解其使用的字节顺序,并根据需要进行调整。