Java 中从 BigDecimal 到字节数组的舍入错误
Rounding error from BigDecimal to byte array in Java
如何正确处理 Java 中 BigDecimal 的转换舍入错误:
BigDecimal -> byte[] -> BigDecimal
我有一个长度为 32 字节的自定义数据类型(是的,32 字节而不是 32 位),我需要将 BigDecimal
的小数部分解码为 byte[]
。
我知道我会失去一些准确性。是否有任何成熟的技术来实现这种转换?
注意:
它是 MxN
形式的定点数据类型,其中 M % 8 == N % 8 == 0
您的定点小数部分可以解释为分数 n/(2[=45] 的分子 n =]256).因此,我建议计算表示 1/(2256) 的 BigDecimal
值(这完全可以表示为 BigDecimal
)并将对它的引用存储在final static
字段。
要将 转换为 a 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
的文档了解它使用的字节顺序,并适当调整。
如何正确处理 Java 中 BigDecimal 的转换舍入错误:
BigDecimal -> byte[] -> BigDecimal
我有一个长度为 32 字节的自定义数据类型(是的,32 字节而不是 32 位),我需要将 BigDecimal
的小数部分解码为 byte[]
。
我知道我会失去一些准确性。是否有任何成熟的技术来实现这种转换?
注意:
它是 MxN
形式的定点数据类型,其中 M % 8 == N % 8 == 0
您的定点小数部分可以解释为分数 n/(2[=45] 的分子 n =]256).因此,我建议计算表示 1/(2256) 的 BigDecimal
值(这完全可以表示为 BigDecimal
)并将对它的引用存储在final static
字段。
要将 转换为 a 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
的文档了解它使用的字节顺序,并适当调整。