关于python:round()似乎无法正确舍入

关于python:round()似乎无法正确舍入

round() doesn't seem to be rounding properly

round()函数的文档指出,您向其传递了一个数字,并将小数点后的位置传递给四舍五入。 因此,它应该这样做:

1
2
n = 5.59
round(n, 1) # 5.6

但是,实际上,老的浮点怪异现象不断蔓延,您会得到:

1
5.5999999999999996

出于UI的目的,我需要显示5.6。 我在Internet上闲逛,发现一些文档取决于我对Python的实现。 不幸的是,这在我的Windows开发机和我尝试过的每台Linux服务器上都会发生。 另请参阅此处。

除了创建自己的回合库之外,还有什么办法可以解决?


格式化无需四舍五入即可正确进行:

1
"%.1f" % n

我不知道它的存储方式,但至少格式化正确:

1
'%.1f' % round(n, 1) # Gives you '5.6'


如果使用小数模块,则可以不使用"舍入"功能进行近似计算。这是我用于舍入的内容,尤其是在编写货币应用程序时:

1
Decimal(str(16.2)).quantize(Decimal('.01'), rounding=ROUND_UP)

这将返回一个十进制数为16.20。


round(5.59, 1)工作正常。问题在于5.6无法精确地用二进制浮点表示。

1
2
3
>>> 5.6
5.5999999999999996
>>>

正如Vinko所说,您可以使用字符串格式对显示进行四舍五入。

如果需要,Python有一个用于十进制算术的模块。


如果执行str(round(n, 1))而不是round(n, 1),则将得到5.6。


您可以将数据类型切换为整数:

1
2
3
4
5
>>> n = 5.59
>>> int(n * 10) / 10.0
5.5
>>> int(n * 10 + 0.5)
56

然后通过插入语言环境的小数点分隔符来显示数字。

但是,吉米的答案更好。


浮点数学运算容易出现轻微但令人讨厌的精度误差。如果可以使用整数或定点,则可以保证精度。


看一下Decimal模块

Decimal"is based on a floating-point
model which was designed with people
in mind, and necessarily has a
paramount guiding principle –
computers must provide an arithmetic
that works in the same way as the
arithmetic that people learn at
school." – excerpt from the decimal
arithmetic specification.

Decimal numbers can be represented
exactly. In contrast, numbers like 1.1
and 2.2 do not have an exact
representations in binary floating
point. End users typically would not
expect 1.1 + 2.2 to display as
3.3000000000000003 as it does with binary floating point.

Decimal提供了一种操作类型,可以轻松编写需要浮点运算的应用程序,并且还需要以人类可读的格式(例如会计)显示这些结果。


确实是个大问题。试用以下代码:

1
print"%.2f" % (round((2*4.4+3*5.6+3*4.4)/8,2),)

显示4.85。然后,您执行以下操作:

1
print"Media = %.1f" % (round((2*4.4+3*5.6+3*4.4)/8,1),)

它显示4.8。您手动计算的确切答案是4.85,但是如果尝试:

1
print"Media = %.20f" % (round((2*4.4+3*5.6+3*4.4)/8,20),)

您会看到事实:浮点存储为分母为2的幂的分数的最接近有限和。


打印吸盘。

1
print '%.1f' % 5.59  # returns 5.6

您可以使用字符串格式运算符%,类似于sprintf。

1
mystring ="%.2f" % 5.5999


完美的作品

1
2
format(5.59, '.1f') # to display
float(format(5.59, '.1f')) #to round

我在做:

1
int(round( x , 0))

在这种情况下,我们首先在单位级别正确舍入,然后转换为整数以避免打印浮点数。

所以

1
2
>>> int(round(5.59,0))
6

我认为这个答案比格式化字符串更好,并且使用round函数对我也更有意义。


码:

1
2
3
4
x1 = 5.63
x2 = 5.65
print(float('%.2f' % round(x1,1)))  # gives you '5.6'
print(float('%.2f' % round(x2,1)))  # gives you '5.7'

输出:

1
2
5.6
5.7

问题仅在最后一位数字为5时出现。 0.045在内部存储为0.044999999999999 ...您可以将最后一位数字简单地增加到6并四舍五入。这将为您提供所需的结果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import re


def custom_round(num, precision=0):
    # Get the type of given number
    type_num = type(num)
    # If the given type is not a valid number type, raise TypeError
    if type_num not in [int, float, Decimal]:
        raise TypeError("type {} doesn't define __round__ method".format(type_num.__name__))
    # If passed number is int, there is no rounding off.
    if type_num == int:
        return num
    # Convert number to string.
    str_num = str(num).lower()
    # We will remove negative context from the number and add it back in the end
    negative_number = False
    if num < 0:
        negative_number = True
        str_num = str_num[1:]
    # If number is in format 1e-12 or 2e+13, we have to convert it to
    # to a string in standard decimal notation.
    if 'e-' in str_num:
        # For 1.23e-7, e_power = 7
        e_power = int(re.findall('e-[0-9]+', str_num)[0][2:])
        # For 1.23e-7, number = 123
        number = ''.join(str_num.split('e-')[0].split('.'))
        zeros = ''
        # Number of zeros = e_power - 1 = 6
        for i in range(e_power - 1):
            zeros = zeros + '0'
        # Scientific notation 1.23e-7 in regular decimal = 0.000000123
        str_num = '0.' + zeros + number
    if 'e+' in str_num:
        # For 1.23e+7, e_power = 7
        e_power = int(re.findall('e\+[0-9]+', str_num)[0][2:])
        # For 1.23e+7, number_characteristic = 1
        # characteristic is number left of decimal point.
        number_characteristic = str_num.split('e+')[0].split('.')[0]
        # For 1.23e+7, number_mantissa = 23
        # mantissa is number right of decimal point.
        number_mantissa = str_num.split('e+')[0].split('.')[1]
        # For 1.23e+7, number = 123
        number = number_characteristic + number_mantissa
        zeros = ''
        # Eg: for this condition = 1.23e+7
        if e_power >= len(number_mantissa):
            # Number of zeros = e_power - mantissa length = 5
            for i in range(e_power - len(number_mantissa)):
                zeros = zeros + '0'
            # Scientific notation 1.23e+7 in regular decimal = 12300000.0
            str_num = number + zeros + '.0'
        # Eg: for this condition = 1.23e+1
        if e_power < len(number_mantissa):
            # In this case, we only need to shift the decimal e_power digits to the right
            # So we just copy the digits from mantissa to characteristic and then remove
            # them from mantissa.
            for i in range(e_power):
                number_characteristic = number_characteristic + number_mantissa[i]
            number_mantissa = number_mantissa[i:]
            # Scientific notation 1.23e+1 in regular decimal = 12.3
            str_num = number_characteristic + '.' + number_mantissa
    # characteristic is number left of decimal point.
    characteristic_part = str_num.split('.')[0]
    # mantissa is number right of decimal point.
    mantissa_part = str_num.split('.')[1]
    # If number is supposed to be rounded to whole number,
    # check first decimal digit. If more than 5, return
    # characteristic + 1 else return characteristic
    if precision == 0:
        if mantissa_part and int(mantissa_part[0]) >= 5:
            return type_num(int(characteristic_part) + 1)
        return type_num(characteristic_part)
    # Get the precision of the given number.
    num_precision = len(mantissa_part)
    # Rounding off is done only if number precision is
    # greater than requested precision
    if num_precision <= precision:
        return num
    # Replace the last '5' with 6 so that rounding off returns desired results
    if str_num[-1] == '5':
        str_num = re.sub('5$', '6', str_num)
    result = round(type_num(str_num), precision)
    # If the number was negative, add negative context back
    if negative_number:
        result = result * -1
    return result

这是我看到回合失败的地方。如果要将这两个数字四舍五入到小数点后该怎么办?
23.45
23.55
我的教育是,通过四舍五入,您应该得到:
23.4
23.6
"规则"是,如果前面的数字为奇数,则应四舍五入,如果前面的数字为偶数,则不四舍五入。
python中的round函数将截断5。


关于什么:

1
round(n,1)+epsilon

推荐阅读