4

当您将 a 转换为floatDecimalDecimal将包含尽可能准确的二进制数表示。准确是很好的,但它并不总是你想要的。由于许多十进制数不能精确地用二进制表示,因此结果Decimal会有些偏差 - 有时有点高,有时有点低。

>>> from decimal import Decimal
>>> for f in (0.1, 0.3, 1e25, 1e28, 1.0000000000001):
    print Decimal(f)

0.1000000000000000055511151231257827021181583404541015625
0.299999999999999988897769753748434595763683319091796875
10000000000000000905969664
9999999999999999583119736832
1.000000000000099920072216264088638126850128173828125

理想情况下,我们希望Decimal四舍五入到最可能的十进制等值。

我尝试转换为,str因为Decimal从字符串创建的将是准确的。不幸的是str,回合有点太多了。

>>> for f in (0.1, 0.3, 1e25, 1e28, 1.0000000000001):
    print Decimal(str(f))

0.1
0.3
1E+25
1E+28
1.0

Decimal有没有办法从浮动中获得一个很好的圆形?

4

2 回答 2

4

事实证明,在将 a 转换为字符串方面repr做得更好。这是进行转换的快速简便的方法。floatstr

>>> for f in (0.1, 0.3, 1e25, 1e28, 1.0000000000001):
    print Decimal(repr(f))

0.1
0.3
1E+25
1E+28
1.0000000000001

在我发现这一点之前,我想出了一种蛮力的四舍五入方法。它具有识别大数精确到 15 位的优点 - 上述repr方法仅识别 1e25 和 1e28 示例的一个有效数字。

from decimal import Decimal,DecimalTuple

def _increment(digits, exponent):
    new_digits = [0] + list(digits)
    new_digits[-1] += 1
    for i in range(len(new_digits)-1, 0, -1):
        if new_digits[i] > 9:
            new_digits[i] -= 10
            new_digits[i-1] += 1
    if new_digits[0]:
        return tuple(new_digits[:-1]), exponent + 1
    return tuple(new_digits[1:]), exponent

def nearest_decimal(f):
    sign, digits, exponent = Decimal(f).as_tuple()
    if len(digits) > 15:
        round_up = digits[15] >= 5
        exponent += len(digits) - 15
        digits = digits[:15]
        if round_up:
            digits, exponent = _increment(digits, exponent)
    while digits and digits[-1] == 0 and exponent < 0:
        digits = digits[:-1]
        exponent += 1
    return Decimal(DecimalTuple(sign, digits, exponent))

>>> for f in (0.1, 0.3, 1e25, 1e28, 1.0000000000001):
    print nearest_decimal(f)

0.1
0.3
1.00000000000000E+25
1.00000000000000E+28
1.0000000000001

编辑:我发现了另一个使用蛮力舍入的理由。repr试图返回一个唯一标识底层float位表示的字符串,但它不一定能确保最后一位数字的准确性。通过减少一位数字,我的四舍五入函数将更多地是您期望的数字。

>>> print Decimal(repr(2.0/3.0))
0.6666666666666666
>>> print dec.nearest_decimal(2.0/3.0)
0.666666666666667

创建的小数repr实际上更准确,但它意味着不存在的精度水平。该nearest_decimal功能在精度和准确性之间提供了更好的匹配。

于 2013-09-19T04:06:06.733 回答
0

我已经在 Pharo Smalltalk 中以Float名为asMinimalDecimalFraction.

假设正确舍入(到最接近的),这与打印将被重新解释为相同浮点数/双精度的最短小数部分完全相同。

在Count number of digits after `.` in floating point numbers查看我的答案 ?更多参考

于 2013-09-19T22:09:23.933 回答