通过 BigDecimal 转换为浮点数的适当比例
Appropriate scale for converting via BigDecimal to floating point
我写了一个任意精度的有理数 class,它需要提供一种转换为浮点数的方法。这可以通过 BigDecimal 直接完成:
return new BigDecimal(num).divide(new BigDecimal(den), 17, RoundingMode.HALF_EVEN).doubleValue();
但这需要在除以十进制数时为比例参数指定一个值。我选择 17 作为初始猜测,因为这大约是双精度浮点数的精度,但我不知道这是否真的正确。
正确使用的数字是多少,定义为使它变大不会使答案更准确的最小数字?
简介
没有足够的精度。
问题中提出的问题等价于:
- 什么精度p保证将任意有理数x转换为p十进制数和然后到浮点数产生最接近 x 的浮点数(或者,在平局的情况下,两个最接近的 x 中的一个)?
要看出这是等价的,请观察问题 returns num
/div
中显示的 BigDecimal
除以选定的小数位数。然后问题是增加小数位数是否可以提高结果的准确性。显然,如果有一个比结果更接近 x 的浮点数,则可以提高精度。因此,我们问的是需要多少小数位才能保证获得最接近的浮点数(或并列的两个浮点数之一)。
由于BigDecimal
提供了舍入方法的选择,我会考虑其中的任何一种是否足够。为了转换为浮点数,我假设使用了舍入到最近的偶数(在转换为 Double
或 Float
时似乎使用了 BigDecimal
)。我使用 IEEE-754 binary64 格式给出证明,Java 用于 Double
,但通过更改 252[=89,该证明适用于任何二进制浮点格式=] 下面用于 2w-1,其中 w 是有效位数中的位数.
证明
BigDecimal
除法的参数之一是舍入方法。 Java’s BigDecimal
has several rounding methods。我们只需要考虑三个,ROUND_UP、ROUND_HALF_UP和ROUND_HALF_EVEN。通过使用各种对称性,其他人的论点类似于下面的论点。
下面,假设我们使用任何大精度p转换为十进制。即p为转换结果的小数位数
设m为有理数252+1+½−10− p。与m相邻的两个binary64数是252+1和252+2。 m更接近第一个,所以这就是我们需要将m先转换为十进制再转换为浮点数的结果。
在十进制中,m是4503599627370497.4999…,其中有p−1尾随9。当使用 ROUND_UP、ROUND_HALF_UP 或 ROUND_HALF_EVEN 四舍五入到 p 有效数字时,结果为 4503599627370497.5 = 252+1+½。 (认识到,在发生舍入的位置,有 16 个尾随 9 被舍弃,实际上是相对于舍入位置的 .9999999999999999 的一小部分。在 ROUND_UP 中,任何非零舍弃量都会导致舍入。在 ROUND_HALF_UP 和 ROUND_HALF_EVEN,在该位置丢弃的数量大于 ½ 会导致四舍五入。)
252+1+½ 与相邻的 binary64 数字 252+1 和 2 同样接近52+2,所以四舍五入法产生 252+2.
因此,结果是252+2,这不是最接近m.
的binary64值
因此,有限精度 p 不足以正确舍入所有有理数。
我写了一个任意精度的有理数 class,它需要提供一种转换为浮点数的方法。这可以通过 BigDecimal 直接完成:
return new BigDecimal(num).divide(new BigDecimal(den), 17, RoundingMode.HALF_EVEN).doubleValue();
但这需要在除以十进制数时为比例参数指定一个值。我选择 17 作为初始猜测,因为这大约是双精度浮点数的精度,但我不知道这是否真的正确。
正确使用的数字是多少,定义为使它变大不会使答案更准确的最小数字?
简介
没有足够的精度。
问题中提出的问题等价于:
- 什么精度p保证将任意有理数x转换为p十进制数和然后到浮点数产生最接近 x 的浮点数(或者,在平局的情况下,两个最接近的 x 中的一个)?
要看出这是等价的,请观察问题 returns num
/div
中显示的 BigDecimal
除以选定的小数位数。然后问题是增加小数位数是否可以提高结果的准确性。显然,如果有一个比结果更接近 x 的浮点数,则可以提高精度。因此,我们问的是需要多少小数位才能保证获得最接近的浮点数(或并列的两个浮点数之一)。
由于BigDecimal
提供了舍入方法的选择,我会考虑其中的任何一种是否足够。为了转换为浮点数,我假设使用了舍入到最近的偶数(在转换为 Double
或 Float
时似乎使用了 BigDecimal
)。我使用 IEEE-754 binary64 格式给出证明,Java 用于 Double
,但通过更改 252[=89,该证明适用于任何二进制浮点格式=] 下面用于 2w-1,其中 w 是有效位数中的位数.
证明
BigDecimal
除法的参数之一是舍入方法。 Java’s BigDecimal
has several rounding methods。我们只需要考虑三个,ROUND_UP、ROUND_HALF_UP和ROUND_HALF_EVEN。通过使用各种对称性,其他人的论点类似于下面的论点。
下面,假设我们使用任何大精度p转换为十进制。即p为转换结果的小数位数
设m为有理数252+1+½−10− p。与m相邻的两个binary64数是252+1和252+2。 m更接近第一个,所以这就是我们需要将m先转换为十进制再转换为浮点数的结果。
在十进制中,m是4503599627370497.4999…,其中有p−1尾随9。当使用 ROUND_UP、ROUND_HALF_UP 或 ROUND_HALF_EVEN 四舍五入到 p 有效数字时,结果为 4503599627370497.5 = 252+1+½。 (认识到,在发生舍入的位置,有 16 个尾随 9 被舍弃,实际上是相对于舍入位置的 .9999999999999999 的一小部分。在 ROUND_UP 中,任何非零舍弃量都会导致舍入。在 ROUND_HALF_UP 和 ROUND_HALF_EVEN,在该位置丢弃的数量大于 ½ 会导致四舍五入。)
252+1+½ 与相邻的 binary64 数字 252+1 和 2 同样接近52+2,所以四舍五入法产生 252+2.
因此,结果是252+2,这不是最接近m.
的binary64值因此,有限精度 p 不足以正确舍入所有有理数。