Java BigDecimal.divide(…)-具有非终止展开式的商的适当刻度

Java BigDecimal.divide(…)-具有非终止展开式的商的适当刻度,java,floating-point,bigdecimal,Java,Floating Point,Bigdecimal,我正在使用BigDecimal进行一些浮点运算。如果将5除以4.2,您将得到一个异常(因为结果是一个非终止扩展,不能用BigDecimal表示),即 在这种情况下,我准备失去一些精度,因此我将使用divide(…)方法,该方法允许提供结果的比例: five.divide(fourPointTwo, 2, RoundingMode.HALF_UP); //Fine, but obviously not 100% accurate 我应该将什么比例传递给此方法,以便结果与我使用两个双精度进行计算一

我正在使用
BigDecimal
进行一些浮点运算。如果将
5
除以
4.2
,您将得到一个异常(因为结果是一个非终止扩展,不能用
BigDecimal
表示),即

在这种情况下,我准备失去一些精度,因此我将使用
divide(…)
方法,该方法允许提供结果的比例:

five.divide(fourPointTwo, 2, RoundingMode.HALF_UP); //Fine, but obviously not 100% accurate
我应该将什么比例传递给此方法,以便结果与我使用两个
双精度进行计算一样准确?

来自:

如果为零或正,则刻度为小数点右侧的位数。如果为负数,则数字的未标度值乘以10,即标度的负数幂。因此,由BigDecimal表示的数字值为(无标度值×10标度)

double
的精度根据值的数量级而变化。根据,它使用52位来存储无符号尾数,因此任何可以用52位表示的整数都可以。这大约是18位小数

此外,
double
使用11位存储指数。所以,像4个小数点这样的精度就可以了。这样,可以表示最多52位的整数乘以2的正幂或负幂,最多10位(一位是指数的符号)。除此之外,你开始失去准确性

double
的额外位存储符号

这样,刻度18+4=22至少与
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.50000000
3.100000
开始。如果将两者分开,则得到
3.387 096 774
。因此,您只需要
3.87
——其余的是备用精度,您可以在进一步的操作中使用,直到您将最后一个结果四舍五入为两位数并将其保存回数据库。

所以您没有具体的精度要求?如果您的精度要求“与
双精度一样好”,如果只使用
double
,不是更容易吗?我不是以英语为母语的人,所以我可能会弄错一些术语,但我希望你能理解。
five.divide(fourPointTwo, 2, RoundingMode.HALF_UP); //Fine, but obviously not 100% accurate