将数字舍入到最接近的整数


229

我一直试图舍入长浮点数,例如:

32.268907563;
32.268907563;
31.2396694215;
33.6206896552;
...

到目前为止没有成功。我想math.ceil(x)math.floor(x)(尽管这或圆形上下,这是不是我要找的)和round(x)它没有任何工作(还是浮点数)。

我能做什么?

编辑:代码:

for i in widthRange:
    for j in heightRange:
        r, g, b = rgb_im.getpixel((i, j))
        h, s, v = colorsys.rgb_to_hsv(r/255.0, g/255.0, b/255.0)
        h = h * 360
        int(round(h))
        print(h)

3
我会尝试int(x)
The Brofessor

那不会给错误吗?以10为底的int()无效文字:
snh_nl

Answers:


366
int(round(x))

将其舍入并将其更改为整数

编辑:

您没有将int(round(h))分配给任何变量。当您调用int(round(h))时,它返回整数,但不执行其他任何操作。您必须将该行更改为:

h = int(round(h))

将新值分配给h

编辑2:

就像@plowman在评论中说的那样,Python round()无法正常运行,这是因为数字作为变量存储的方式通常不是您在屏幕上看到的方式。有很多答案可以解释此行为:

round()似乎无法正确舍入

避免此问题的一种方法是使用此答案所述的十进制:https : //stackoverflow.com/a/15398691/4345659

为了使此答案正确运行而不使用额外的库,使用自定义舍入函数会很方便。经过大量的更正之后,我想出了以下解决方案,据我测试避免了所有存储问题。它基于使用通过repr()(NOT str()!)获得的字符串表示形式。它看起来很黑,但这是我发现解决所有问题的唯一方法。它同时适用于Python2和Python3。

def proper_round(num, dec=0):
    num = str(num)[:str(num).index('.')+dec+2]
    if num[-1]>='5':
        return float(num[:-2-(not dec)]+str(int(num[-2-(not dec)])+1))
    return float(num[:-1])

测试:

>>> print(proper_round(1.0005,3))
1.001
>>> print(proper_round(2.0005,3))
2.001
>>> print(proper_round(3.0005,3))
3.001
>>> print(proper_round(4.0005,3))
4.001
>>> print(proper_round(5.0005,3))
5.001
>>> print(proper_round(1.005,2))
1.01
>>> print(proper_round(2.005,2))
2.01
>>> print(proper_round(3.005,2))
3.01
>>> print(proper_round(4.005,2))
4.01
>>> print(proper_round(5.005,2))
5.01
>>> print(proper_round(1.05,1))
1.1
>>> print(proper_round(2.05,1))
2.1
>>> print(proper_round(3.05,1))
3.1
>>> print(proper_round(4.05,1))
4.1
>>> print(proper_round(5.05,1))
5.1
>>> print(proper_round(1.5))
2.0
>>> print(proper_round(2.5))
3.0
>>> print(proper_round(3.5))
4.0
>>> print(proper_round(4.5))
5.0
>>> print(proper_round(5.5))
6.0
>>> 
>>> print(proper_round(1.000499999999,3))
1.0
>>> print(proper_round(2.000499999999,3))
2.0
>>> print(proper_round(3.000499999999,3))
3.0
>>> print(proper_round(4.000499999999,3))
4.0
>>> print(proper_round(5.000499999999,3))
5.0
>>> print(proper_round(1.00499999999,2))
1.0
>>> print(proper_round(2.00499999999,2))
2.0
>>> print(proper_round(3.00499999999,2))
3.0
>>> print(proper_round(4.00499999999,2))
4.0
>>> print(proper_round(5.00499999999,2))
5.0
>>> print(proper_round(1.0499999999,1))
1.0
>>> print(proper_round(2.0499999999,1))
2.0
>>> print(proper_round(3.0499999999,1))
3.0
>>> print(proper_round(4.0499999999,1))
4.0
>>> print(proper_round(5.0499999999,1))
5.0
>>> print(proper_round(1.499999999))
1.0
>>> print(proper_round(2.499999999))
2.0
>>> print(proper_round(3.499999999))
3.0
>>> print(proper_round(4.499999999))
4.0
>>> print(proper_round(5.499999999))
5.0

最后,正确的答案将是:

# Having proper_round defined as previously stated
h = int(proper_round(h))

编辑3:

测试:

>>> proper_round(6.39764125, 2)
6.31 # should be 6.4
>>> proper_round(6.9764125, 1)
6.1  # should be 7

此处的陷阱是,dec第-小数位数可以为9,如果dec+1-th位数> = 5,则9将变为0,并且应将1携带至dec-1第-位数。

如果考虑到这一点,我们将得到:

def proper_round(num, dec=0):
    num = str(num)[:str(num).index('.')+dec+2]
    if num[-1]>='5':
      a = num[:-2-(not dec)]       # integer part
      b = int(num[-2-(not dec)])+1 # decimal part
      return float(a)+b**(-dec+1) if a and b == 10 else float(a+str(b))
    return float(num[:-1])

在上述情况下b = 10,以前的版本将串联在一起ab这将导致10尾随0消失的位置的串联。此版本b会根据适当地转换为右小数位dec


2
print(“ 4.5)”,int(round(4.5)))#给了我4 print(“ 5.5)”,int(round(5.5)))#给了我6:,(
Komm

它与Python版本有关。它使用Python 2.7.9给了我5和6,正如你所说的,使用Python 3.4.2给了我4和6
francisco sollima

1
值得注意的是:此解决方案并没有按照您期望的方式进行处理。例如,int(round(4.5))四舍五入为4,而int(round(4.500001))正确舍入为
5。– plowman

如果您想要一个整数,那么round(x)在Python 3.6.2中就足够了(可能还需要较低的版本)。结果已经是int类型。注意:round(x, n)将为float类型。
Elmex80s

1
这不适用于112439.50093565206。给出o / p-> 11253.0。该死的怪异.. !!!!
ajin


20

round(value,significantDigit)是普通的解决方案,但是,当舍入值以结束时,这并不像从数学角度所期望的那样起作用5。如果5在四舍五入到的数字后面紧跟着数字,则有时仅按预期将这些值四舍五入(即8.005四舍五入为两位小数8.01)。对于某些由于浮点数学的怪异而导致的值,它们会四舍五入!

>>> round(1.0005,3)
1.0
>>> round(2.0005,3)
2.001
>>> round(3.0005,3)
3.001
>>> round(4.0005,3)
4.0
>>> round(1.005,2)
1.0
>>> round(5.005,2)
5.0
>>> round(6.005,2)
6.0
>>> round(7.005,2)
7.0
>>> round(3.005,2)
3.0
>>> round(8.005,2)
8.01

奇怪的。

假设您的意图是对科学中的统计数据进行传统的四舍五入,这是一个方便的包装方法,可以使round函数按预期工作,并且需要import额外的功能,例如Decimal

>>> round(0.075,2)

0.07

>>> round(0.075+10**(-2*5),2)

0.08

啊哈!因此,基于此我们可以创建一个函数...

def roundTraditional(val,digits):
   return round(val+10**(-len(str(val))-1), digits)

基本上,这会增加一个值,该值保证小于您要在其上使用的字符串的最小给定数字round。通过添加少量它保留的round在大多数情况下的行为,而现在如果确保数字逊于一个是四舍五入到是5它四舍五入,如果是4它几轮下来。

使用该方法的目的10**(-len(val)-1)是故意的,因为它是您可以添加的最大的小数字以强制移位,同时还要确保所添加的值不会改变舍入,即使.缺少小数点也是如此。我可以使用10**(-len(val))条件if (val>1)减法来减去1更多...但是总要减去法则比较简单,1因为这不会改变此解决方法可以正确处理的十进制数的适用范围。如果您的值达到该类型的限制,则此方法将失败,但将失败,但是对于几乎所有有效十进制值的范围,它都应起作用。

您也可以使用十进制库来完成此操作,但是我建议的包装器更简单,在某些情况下可能更受欢迎。


编辑:感谢Blckknght指出,5条纹情况只发生在某些值。另外,此答案的较早版本还不够明确,仅当紧邻要舍入的数字的下标为时才发生5奇数舍入行为。


我不确定为什么您会认为小数5位的最后一位总是四舍五入。这不是一个快速测试我只是用数字做了类似的情况1.52.53.5等和1.051.151.251.35四舍五入至小数点后一位。第一组(精确的一半四舍五入为小整数)始终四舍五入为偶数整数。后者集的舍入不一致,可能是由于某些值的不精确二进制表示。具有精确二进制表示形式的浮点数(例如1.25舍入)具有甚至最低有效数字,但其他浮点数似乎是随机舍入的。
Blckknght

有趣的...你是对的。 round(4.0005,3)给予4.0round(1.0005,3)给予1.0,但round(2.0005,3)给予2.001round(3.0005,3)给予3.001。但这就是为什么我提出的解决方案是必要的原因……在这种重大情况下,您不知道从股票回合中可以获得什么结果!
Jason R. Mick

谢谢你 出现此问题时,您的功能将派上用场。
TMWP

1
您是否打算, digits在该退货声明的末尾加上?无双关语。(平均值我的意思)
user3342816

是的,确实应该在那里。好收获……没有其他人感到惊讶!将为那些利用解决方案的人节省一些挫败感。:-)
Jason R. Mick

15

对于正面,请尝试

int(x + 0.5)

要使其也适用于底片,请尝试

int(x + (0.5 if x > 0 else -0.5))

int()就像下层函数一样工作,因此您可以利用此属性。这绝对是最快的方法。


4
不适用于底片>>> x=-0.999 >>> int(x), round(x), int(x+0.5) (0, -1.0, 0)
user2907934'1

3
如果您关心极端情况,请不要使用“添加0.5和下限”技术-有些值可能无法达到您的期望!见stackoverflow.com/a/47302585/2732969在C ++采取和stackoverflow.com/a/38744026/2732969在这个问题的答案。
Anon

我需要一种快速的方法,它不必很准确,也不会有很多极端情况,在我的情况下,极端情况下的错误并不重要。因此,对于某些优先考虑速度的特殊情况,这绝对是我的最佳选择。不建议精度或准确性。
AgentM

11

按照IEEE 754的规定,Python不仅会做一半甚至一半的运算吗?

小心重新定义或使用“非标准”舍入…

(另请参阅https://stackoverflow.com/a/33019948/109839


2
这个答案还不清楚。Round half to even绝对不是IEEE 754所规定的,而是仅是标准描述的几种取整选项之一。Round to nearest, ties away from zero(即大多数人期望的行为)也是一种选择,并且是C / C ++中的默认设置。
电话

我同意,措辞相当混乱。我的意思是Python是四舍五入半heven(见的表底docs.python.org/3.7/library/...这里round解释),它是这样做的根据办法“轮一半,甚至”被规定按照标准工作(或描述)。
马皮奥

8

您也可以使用numpy,假设您正在使用python3.x,这是一个示例

import numpy as np
x = 2.3
print(np.rint(x))
>>> 2.0

7

您的解决方案是在不指定第二个参数(小数位数)的情况下调用round

>>> round(0.44)
0
>>> round(0.64)
1

比起更好的结果

>>> int(round(0.44, 2))
0
>>> int(round(0.64, 2))
0

来自Python文档,网址为 https://docs.python.org/3/library/functions.html#round

舍入(数字[,n位数字])

返回数字舍入到小数点后的n位精度。如果省略ndigits或为None,则返回与其输入最接近的整数。

注意

针对float的round()行为可能令人惊讶:例如,round(2.675,2)给出2.67,而不是预期的2.68。这不是错误:这是由于大多数十进制小数不能完全表示为浮点数的结果。有关更多信息,请参见浮点算法:问题和限制。


1

如果您需要(例如)A的两位数近似值,则 int(A*100+0.5)/100.0则将完成您要查找的操作。

如果需要三位数的近似值,请乘以1000除以此类推。


1

这样的事情也应该起作用

import numpy as np    

def proper_round(a):
    '''
    given any real number 'a' returns an integer closest to 'a'
    '''
    a_ceil = np.ceil(a)
    a_floor = np.floor(a)
    if np.abs(a_ceil - a) < np.abs(a_floor - a):
        return int(a_ceil)
    else:
        return int(a_floor)

0

为此,我建议您做以下事情-

int(round(x))

这将为您提供最接近的整数。

希望这可以帮助!!


0

我使用并建议以下解决方案(python3.6):

y = int(x + (x % (1 if x >= 0 else -1)))

它适用于半数(正数和负数),甚至比int(round(x))更快:

round_methods = [lambda x: int(round(x)), 
                 lambda x: int(x + (x % (1 if x >= 0 else -1))),
                 lambda x: np.rint(x).astype(int),
                 lambda x: int(proper_round(x))]

for rm in round_methods:
    %timeit rm(112.5)
Out:
201 ns ± 3.96 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
159 ns ± 0.646 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
925 ns ± 7.66 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
1.18 µs ± 8.66 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

for rm in round_methods:
    print(rm(112.4), rm(112.5), rm(112.6))
    print(rm(-12.4), rm(-12.5), rm(-12.6))
    print('=' * 11)

Out:
112 112 113
-12 -12 -13
===========
112 113 113
-12 -13 -13
===========
112 112 113
-12 -12 -13
===========
112 113 113
-12 -13 -13
===========
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.