介绍
没有有限的精度就足够了。
问题中提出的问题相当于:
- 什么精度p保证将任何有理数x转换为p十进制数字,然后再转换为浮点数会产生最接近x的浮点数(或者,在平局的情况下,两个最接近的x之一)?
要看到这是等价的,请注意BigDecimal
问题中显示的除法将num
/返回div
到选定的小数位数。然后问题询问增加小数位数是否可以提高结果的准确性。显然,如果有一个浮点数比结果更接近x,那么精度可以提高。因此,我们询问需要多少小数位才能保证获得最接近的浮点数(或并列的两个浮点数之一)。
由于BigDecimal
提供了舍入方法的选择,我将考虑其中任何一个是否足够。对于转换为浮点数,我假设使用 round-to-nearest-ties-to-even (转换为orBigDecimal
时似乎使用)。我使用 IEEE-754 binary64 格式提供证明,Java 用于,但证明适用于任何二进制浮点格式,方法是将下面使用的 2 52更改为 2 w -1,其中w是有效数字。Double
Float
Double
证明
除法的参数之一BigDecimal
是舍入方法。JavaBigDecimal
有几种舍入方法。我们只需要考虑三个,ROUND_UP、ROUND_HALF_UP和ROUND_HALF_EVEN。通过使用各种对称性,其他参数类似于下面的参数。
在下文中,假设我们使用任何大精度p转换为十进制。也就是说,p是转换结果中的小数位数。
令m为有理数 2 52 +1+½−10 -<i>p。与m相邻的两个 binary64 数是 2 52 +1 和 2 52 +2。m更接近第一个,所以这是我们需要先将m转换为十进制,然后再转换为浮点的结果。
在十进制中,m是 4503599627370497.4999…,其中有p -1 个尾随 9。当使用 ROUND_UP、ROUND_HALF_UP 或 ROUND_HALF_EVEN四舍五入到p个有效数字时,结果为 4503599627370497.5 = 2 52 +1+½。(认识到,在发生舍入的位置,有 16 个尾随 9 被丢弃,实际上是舍入位置的 0.9999999999999999 的一小部分。在 ROUND_UP 中,任何非零丢弃量都会导致向上舍入。在 ROUND_HALF_UP 和 ROUND_HALF_EVEN 中,a在该位置丢弃大于 ½ 的量会导致向上舍入。)
2 52 +1+½ 与相邻的二进制 64 数字 2 52 +1 和 2 52 +2同样接近,因此四舍五入法产生 2 52 +2。
因此,结果是 2 52 +2,这不是最接近m的 binary64 值。
因此,没有有限精度p足以正确舍入所有有理数。