在 Java 中将错误从 BigDecimal 舍入到字节数组



在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_EVENRoundingMode.HALF_UP. 然后通过BigDecimal.unscaledValue()获取结果的BigInteger未缩放值(在数值上应等于缩放值,因为整数值应具有缩放 0)。 然后,BigInteger.toByteArray()会给你一个与你所追求的东西密切相关的byte[]*

要走另一条路,你几乎可以逆转这个过程。BigDecimal有一个构造函数,它接受与您的表示非常密切相关的byte[]。 使用该构造函数,将byte[]转换为BigInteger,然后通过适当的构造函数转换为BigDecimal。 乘以存储的 1/(2256) 值以获得所需的小数部分。


*这里最大的技巧可能涉及适当地摆动标志。 如果您的BigDecimal可能是负数,那么您可能希望在转换为byte[]之前先获取它们的绝对值。 更重要的是,BigInteger产生和消费的byte[]使用二进制补码表示(带有符号位),而我想你会想要一个无符号的纯二进制表示。 这主要意味着在转换时需要留出额外的位 - 因此需要整个额外的字节。 还要注意字节顺序;检查BigInteger的文档以了解其使用的字节顺序,并根据需要进行调整。

最新更新