Round()似乎舍入不正确

()函数的文档指出,您传递给它一个数字,以及小数后的位置到整数。因此,它 应该这样做:

n = 5.59
round(n, 1) # 5.6

但是,实际上,古老的浮点数奇怪的东西悄悄地出现了,你会得到:

5.5999999999999996

为了用户界面的目的,我需要显示 5.6。我在互联网上查找了一下,发现了一些 文件,它们取决于我的 Python 实现。不幸的是,这种情况在我的 Windows 开发计算机和我尝试的每个 Linux 服务器上都会发生。这里也有.

除了创建我自己的圆形图书馆,还有什么办法可以解决这个问题吗?

262507 次浏览

那么:

round(n,1)+epsilon

我无法控制它的存储方式,但至少格式正确:

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

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

>>> n = 5.59
>>> int(n * 10) / 10.0
5.5
>>> int(n * 10 + 0.5)
56

然后通过插入现场的小数点来显示数字。

然而,吉米的回答更好。

可以使用与 sprintf 类似的字符串格式操作符 %

mystring = "%.2f" % 5.5999

你得到’5.6’如果你做 str(round(n, 1))而不仅仅是 round(n, 1)

浮点数很容易出现轻微但恼人的精度错误。如果您能够处理整数或不动点,您将保证精度。

吸盘。

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

即使不用舍入,格式化也能正确工作:

"%.1f" % n

round(5.59, 1)运行正常,问题是5.6不能精确地用二进制浮点数表示。

>>> 5.6
5.5999999999999996
>>>

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

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

看看 十进制模块

“ Decimal”基于浮点数 这个模型是用人设计的 在脑海中,必然有一个 最高指导原则 计算机必须提供一个算术 它的工作方式与 人们学习的算术 学校。”-摘自小数 算术规范算术规范。

还有

可以表示十进制数 没错。相比之下,像1.1这样的数字 2.2没有一个精确的 二进制浮点数表示法 最终用户通常不会 期望1.1 + 2.2显示为 3.300000000000000003,就像它对二进制浮点数所做的那样。

Decimal 提供的操作使得编写需要浮点运算的应用程序变得非常容易,而 还有需要以人类可读的格式显示这些结果,例如会计。

如果使用 Decimal 模块,可以不使用‘ round’函数进行近似。下面是我一直在使用的舍入方法,尤其是在编写货币应用程序时:

from decimal import Decimal, ROUND_UP


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

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

这确实是个大问题。试试这段代码:

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

它显示4.85。然后你做:

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

它显示4.8。你手工计算的精确答案是4.85,但如果你尝试:

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

你可以看到事实: 浮点数被存储为分母为2的幂的最接近的有限分数之和。

效果很好

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

我正在做:

int(round( x , 0))

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

所以

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

我认为这个答案比格式化字符串更有效,而且对我来说使用 round 函数更有意义。

这就是我看到的舍入失败的地方。如果你想把这两个数字舍入到小数点后的一位呢? 23.45 23.55元 我接受的教育是,通过四舍五入,你应该得到: 23.4 23.6 “规则”是,如果前面的数字是奇数,你应该四舍五入,而不是四舍五入,如果前面的数字是偶数。 Python 中的 round 函数简单地截断了5。

密码:

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'

产出:

5.6
5.7

问题只在于最后一个数字是5。例如,0.045在内部存储为0.0449999999999999999... ... 您可以简单地将最后一个数字增加到6并四舍五入。这会给你想要的结果。

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

在这种情况下,我会完全避免依赖 round()

print(round(61.295, 2))
print(round(1.295, 2))

将输出

61.3
1.29

如果需要整数四舍五入到最接近的整数,这不是一个理想的输出。为了绕过这种行为,使用 math.ceil()(或者 math.floor(),如果你想四舍五入) :

from math import ceil
decimal_count = 2
print(ceil(61.295 * 10 ** decimal_count) / 10 ** decimal_count)
print(ceil(1.295 * 10 ** decimal_count) / 10 ** decimal_count)

输出

61.3
1.3

希望能帮上忙。

另一个可能的选择是:

def hard_round(number, decimal_places=0):
"""
Function:
- Rounds a float value to a specified number of decimal places
- Fixes issues with floating point binary approximation rounding in python
Requires:
- `number`:
- Type: int|float
- What: The number to round
Optional:
- `decimal_places`:
- Type: int
- What: The number of decimal places to round to
- Default: 0
Example:
```
hard_round(5.6,1)
```
"""
return int(number*(10**decimal_places)+0.5)/(10**decimal_places)

这里有一个简单的方法可以将浮点数四舍五入到小数点后的任意位数,并且在2021年仍然有效!

float_number = 12.234325335563
rounded = round(float_number, 3) # 3 is the number of decimal places to be returned.You can pass any number in place of 3 depending on how many decimal places you want to return.
print(rounded)

这个会打印出来

12.234