BigDecimal.divide(...) - 具有非终止扩展的商的适当比例
我正在使用 BigDecimal 进行一些浮点数学运算。如果将 5
除以 4.2
,您将得到一个异常(因为结果具有非终止扩展,无法用 BigDecimal
表示) )即
BigDecimal five = new BigDecimal("5");
BigDecimal fourPointTwo = new BigDecimal("4.2");
five.divide(fourPointTwo) // ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
我准备在这种情况下失去一些精度,因此我将使用 divide(...)
方法,该方法允许提供结果的比例:
five.divide(fourPointTwo, 2, RoundingMode.HALF_UP); //Fine, but obviously not 100% accurate
我应该使用什么比例传递给这个方法,以便结果像我一样准确使用两个双精度
执行计算?
I'm using BigDecimal
for some floating-point math. If you divide 5
by 4.2
you'll get an exception (as the result has a non-terminating expansion which cannot be represented by a BigDecimal
) i.e.
BigDecimal five = new BigDecimal("5");
BigDecimal fourPointTwo = new BigDecimal("4.2");
five.divide(fourPointTwo) // ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
I'm prepared to lose some precision in this case, so I am going to use the divide(...)
method which allows a scale for the result to be provided:
five.divide(fourPointTwo, 2, RoundingMode.HALF_UP); //Fine, but obviously not 100% accurate
What scale should I pass to this method so that the result is as accurate as if I had performed the calculation using two doubles
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
来自 BigDecimal 类的 javadocs:
double
的精度根据值的数量级而变化。根据这个 ,它使用52位来存储无符号尾数,因此任何可以用52位表示的整数都可以。这大约是 18 位十进制数字。此外,
double
使用 11 位来存储指数。所以,像 4 位小数精度就可以了。这样,可以表示任何最多 52 位的整数乘以 2 的正或负幂,最多 10 位(一位是指数的符号)。除此之外,你开始失去精确度。double
的额外位存储符号。这样,scale 18 + 4 = 22 将至少与
double
一样精确。From the javadocs of the BigDecimal class:
The precision of
double
varies accordingly to the order of magnitude of the value. According to this, it uses 52 bits to store the unsigned mantissa, so any integer that may be represented with 52 bits will be ok. This will be roughly 18 decimal digits.Further,
double
uses 11 bits to store the exponent. So, something like 4 decimal precision will do. This way, any integer up to 52 bits multiplied by a positive or negative power of 2 with at most 10 bits may be represented (one bit is the sign of the expoent). Beyond that, you start to lose precision.The extra bit of
double
stores the sign.This way, scale 18 + 4 = 22 will be at least as precise as
double
.您的问题称为“舍入误差”或“舍入误差”。示例:
您有两个数字
a
和b
。您知道每个数字都有一定的精度(即您有信心的数字位数),这意味着其他数字都是“随机”噪声。想象一下
b
的精度为两位数。(b*100)-int(b*100)
的结果将是随机的,因为该操作会删除所有“正确”的数字。这些误差的传播取决于数学运算。一些示例:
当数字相加时,误差范围也会增加。如果
a
和b
的精度为 2,则将它们相加可能会将分数的第二位数字变成垃圾:0.003 + 0.008 = 0.011乘法会使误差快速增大乘法使
除法减少了误差范围 (0.003 / 3 = 0.001)
因此,如果你想要一个正确的答案,你必须计算你的所有操作的误差范围代码遵循上述规则。 链接任何人?
当然,这通常不是一个选择。所以你需要考虑你可以忍受多少错误。例如,如果您对金融数据进行数学运算,那么 10 或 20 的精度通常就足够了,因为在误差增长到值的重要部分之前,您有足够的位可以“浪费”多次数学运算。
示例:您从
10.500 000 000
和3.100 000 000
开始。如果将两者相除,则得到3.387 096 774
。由此,您只需要3.87
- 其余的都是备用精度,您可以在进一步的操作中使用它,直到将最后结果四舍五入到两位数并将其保存回数据库中。Your problem is called "round-off error" or "rounding error". Example:
You have two numbers
a
andb
. You know that each has a certain precision (i.e. number of digits that you're confident of) which means that every other digit is "random" noise.Imagine
b
has a precision of two digits. The result of(b*100)-int(b*100)
will be random since the operation cuts away all "correct" digits.These errors propagate depending on the mathematical operation. Some examples:
Errors margins add when the numbers are added. If
a
andb
have a precision of two, adding them might turn the second digit of the fraction into garbage: 0.003 + 0.008 = 0.011Multiplication grows the error fast and exponential functions grow it even faster.
Division reduces the error margin (0.003 / 3 = 0.001)
So if you want a correct answer, you must calculate the error margins of all operations in your code following the rules outlined above. Link anyone?
Of course, this is usually not an option. So you need to think what amount of error you can live with. For example if you do math on financial data, a precision of 10 or 20 is generally enough because you have enough bits to "waste" for several mathematical operations before the error grows into significant parts of the value.
Example: You start with
10.500 000 000
and3.100 000 000
. If you divide the two, you get3.387 096 774
. From that, you only need3.87
- the rest is spare precision which you can use up in further operations until you round the last result to two digits and save it back in the database.