BigDecimal.divide(...) - 具有非终止扩展的商的适当比例

发布于 2024-12-21 19:39:00 字数 619 浏览 5 评论 0原文

我正在使用 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

国粹 2024-12-28 19:39:00

来自 BigDecimal 类的 javadocs

如果为零或正数,则小数位数为小数点右侧的位数。如果为负,则该数字的未缩放值乘以 10 的缩放负次方。因此,BigDecimal 表示的数字值为 (unscaledValue × 10-scale)。

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

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

double 的额外位存储符号。

这样,scale 18 + 4 = 22 将至少与 double 一样精确。

From the javadocs of the BigDecimal class:

If zero or positive, the scale is the number of digits to the right of the decimal point. If negative, the unscaled value of the number is multiplied by ten to the power of the negation of the scale. The value of the number represented by the BigDecimal is therefore (unscaledValue × 10-scale).

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.

夏末 2024-12-28 19:39:00

您的问题称为“舍入误差”或“舍入误差”。示例:

您有两个数字 ab。您知道每个数字都有一定的精度(即您有信心的数字位数),这意味着其他数字都是“随机”噪声。

想象一下 b 的精度为两位数。 (b*100)-int(b*100) 的结果将是随机的,因为该操作会删除所有“正确”的数字。

这些误差的传播取决于数学运算。一些示例:

  • 当数字相加时,误差范围也会增加。如果 ab 的精度为 2,则将它们相加可能会将分数的第二位数字变成垃圾:0.003 + 0.008 = 0.011

  • 乘法会使误差快速增大乘法使

  • 除法减少了误差范围 (0.003 / 3 = 0.001)

因此,如果你想要一个正确的答案,你必须计算你的所有操作的误差范围代码遵循上述规则。 链接任何人?

当然,这通常不是一个选择。所以你需要考虑你可以忍受多少错误。例如,如果您对金融数据进行数学运算,那么 10 或 20 的精度通常就足够了,因为在误差增长到值的重要部分之前,您有足够的位可以“浪费”多次数学运算。

示例:您从 10.500 000 0003.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 and b. 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 and b have a precision of two, adding them might turn the second digit of the fraction into garbage: 0.003 + 0.008 = 0.011

  • Multiplication 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 and 3.100 000 000. If you divide the two, you get 3.387 096 774. From that, you only need 3.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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文