【问题标题】:Round up to Second Decimal Place in Python在 Python 中向上舍入到第二个小数位
【发布时间】:2012-03-03 04:28:33
【问题描述】:

如何在python中将一个数字四舍五入到小数点后第二位?例如:

0.022499999999999999

应该向上取整到0.03

0.1111111111111000

应该向上取整到0.12

如果有任何值在小数点后第三位,我希望它始终向上舍入,在小数点后留下 2 个值。

【问题讨论】:

标签: python rounding


【解决方案1】:

Python 包含round() 函数,其中lets you specify 是您想要的位数。来自文档:

round(x[, n])

返回浮点值 x 舍入到小数点后 n 位。如果省略 n,则默认为零。结果是一个浮点数。值四舍五入到最接近的 10 的负 n 次方倍数;如果两个倍数相等,则从 0 开始舍入(例如,round(0.5) 为 1.0,round(-0.5) 为 -1.0)。

因此,您可能希望使用round(x, 2) 进行正常舍入。为确保数字始终向上四舍五入,您需要使用ceil(x) 函数。同样,要舍入 使用floor(x)

【讨论】:

  • 好建议,但它并没有像 OP 似乎要求的那样 向上
  • “四舍五入”与普通四舍五入不同。查看问题中的示例。
  • @Mark 因为添加确切的代码来执行ceil 意味着复制你的答案,所以我将(几乎)保持原样并支持你的答案。
【解决方案2】:
from math import ceil

num = 0.1111111111000
num = ceil(num * 100) / 100.0

请参阅:
math.ceil documentation
round documentation - 无论如何,您可能都想检查一下以供将来参考

【讨论】:

  • 这里不需要round()——它不会以任何方式改变结果。
  • 在以下情况下给出错误结果:math.ceil((1.11 * 100.0)) / 100.0 变成1.12 因为:1.11 * 100.0 具有值111.00000000000001
  • @nimeshkiranverma 请参阅Is floating point math broken? 如果您需要精确的十进制结果,请使用decimal module
  • 根据@nimeshkiranverma 的观察,您确实需要round() 才能获得所需的结果:math.ceil(round(1.11 * 100.0)) / 100.0
【解决方案3】:
x = math.ceil(x * 100.0) / 100.0

【讨论】:

  • 在我意识到这比我的解决方案更 Python 之前,我不得不盯着它看了一会儿。
【解决方案4】:

更新答案:
正如@jpm 在 cmets 中指出的那样,我原来的答案的问题是边界处的行为。 Python 3 使这变得更加困难,因为它使用“银行家”四舍五入而不是“老派”四舍五入。然而,在研究这个问题时,我发现了一个使用 decimal 库的更好的解决方案。

import decimal

def round_up(x, place=0):
    context = decimal.getcontext()
    # get the original setting so we can put it back when we're done
    original_rounding = context.rounding
    # change context to act like ceil()
    context.rounding = decimal.ROUND_CEILING

    rounded = round(decimal.Decimal(str(x)), place)
    context.rounding = original_rounding
    return float(rounded)

或者如果你真的只想要一个单线:

import decimal
decimal.getcontext().rounding = decimal.ROUND_CEILING

# here's the one-liner
float(round(decimal.Decimal(str(0.1111)), ndigits=2))
>> 0.12

# Note: this only affects the rounding of `Decimal`
round(0.1111, ndigits=2)
>> 0.11

这里有一些例子:

round_up(0.022499999999999999, 2)
>> 0.03
round_up(0.1111111111111000, 2)
>> 0.12
round_up(0.1111111111111000, 3)
>> 0.112

round_up(3.4)
>> 4.0

# @jpm - boundaries do what we want
round_up(0.1, 2)
>> 0.1
round_up(1.1, 2)
>> 1.1

# Note: this still rounds toward `inf`, not "away from zero"
round_up(2.049, 2)
>> 2.05
round_up(-2.0449, 2)
>> -2.04

我们也可以用它来四舍五入到小数点的左边:

round_up(11, -1)
>> 20

我们不乘以 10,从而避免in this answer 提到的溢出。

round_up(1.01e308, -307)
>> 1.1e+308

原始答案(不推荐)
这取决于您在考虑正数和负数时想要的行为,但是如果您想要总是四舍五入到更大的值(例如 2.0449 -> 2.05、-2.0449 -> -2.04),那么您可以这样做:

round(x + 0.005, 2)

或者更喜欢一点:

def round_up(x, place):
    return round(x + 5 * 10**(-1 * (place + 1)), place)

这似乎也可以如下工作:

round(144, -1)
# 140
round_up(144, -1)
# 150
round_up(1e308, -307)
# 1.1e308

【讨论】:

  • 这不能保证有效...例如:round(0.1 + 0.005, 2) == 0.11round(1.1 + 0.005, 2) == 1.10
  • @jpm:好点。我调查了一下,结果发现边界很难用round来正确处理,尤其是现在round使用“银行家”四舍五入而不是“老派四舍五入”。我已经用更好的解决方案更新了我的答案。
【解决方案5】:

根据 Edwin 的回答推断:

from math import ceil, floor
def float_round(num, places = 0, direction = floor):
    return direction(num * (10**places)) / float(10**places)

使用方法:

>>> float_round(0.21111, 3, ceil)  #round up
>>> 0.212
>>> float_round(0.21111, 3)        #round down
>>> 0.211
>>> float_round(0.21111, 3, round) #round naturally
>>> 0.211

【讨论】:

  • 在下列情况下给出错误的结果:math.ceil((1.11 * 100.0)) / 100.0 变成 1.12 因为:1.11 * 100.0 具有值 111.00000000000001
【解决方案6】:

请注意,ceil(num * 100) / 100 技巧会在某些退化输入(如 1e308)上崩溃。这可能不会经常出现,但我可以告诉你这只是花了我几天的时间。为避免这种情况,“如果”ceil()floor() 采用小数位参数就好了,就像 round() 那样......同时,有人知道一个不会在这样的输入上崩溃的干净替代方案吗?我对decimal 包有一些希望,但它似乎也死了:

>>> from math import ceil
>>> from decimal import Decimal, ROUND_DOWN, ROUND_UP
>>> num = 0.1111111111000
>>> ceil(num * 100) / 100
0.12
>>> float(Decimal(num).quantize(Decimal('.01'), rounding=ROUND_UP))
0.12
>>> num = 1e308
>>> ceil(num * 100) / 100
Traceback (most recent call last):
  File "<string>", line 301, in runcode
  File "<interactive input>", line 1, in <module>
OverflowError: cannot convert float infinity to integer
>>> float(Decimal(num).quantize(Decimal('.01'), rounding=ROUND_UP))
Traceback (most recent call last):
  File "<string>", line 301, in runcode
  File "<interactive input>", line 1, in <module>
decimal.InvalidOperation: [<class 'decimal.InvalidOperation'>]

当然,有人可能会说崩溃是此类输入的唯一合理行为,但我认为导致问题的不是四舍五入而是乘法(这就是为什么,例如 1e306 不会崩溃),以及更简洁地实现第 n 位取整 fn 将避免乘法破解。

【讨论】:

  • 你使用Decimal遇到的问题是量化表达式的结果需要311位来表示,当前精度太小。如果你事先做一个from decimal import getcontext; getcontext().prec = 400,这将“工作”,对于一些“工作”的价值。或者您可能会注意到,任何绝对值大于 2**52 的浮点数必须已经是整数,因此四舍五入将无效。是的,我同意如果“ceil”和“floor”采用小数位参数会很好。
【解决方案7】:

这是一个更通用的单行,适用于任何数字:

import math
def ceil(number, digits) -> float: return math.ceil((10.0 ** digits) * number) / (10.0 ** digits)

示例用法:

>>> ceil(1.111111, 2)
1.12

警告:如 nimeshkiranverma 所述:

>>> ceil(1.11, 2) 
1.12  #Because: 1.11 * 100.0 has value 111.00000000000001

【讨论】:

    【解决方案8】:
    def round_up(number, ndigits=None):
        # start by just rounding the number, as sometimes this rounds it up
        result = round(number, ndigits if ndigits else 0)
        if result < number:
            # whoops, the number was rounded down instead, so correct for that
            if ndigits:
                # use the type of number provided, e.g. float, decimal, fraction
                Numerical = type(number)
                # add the digit 1 in the correct decimal place
                result += Numerical(10) ** -ndigits
                # may need to be tweaked slightly if the addition was inexact
                result = round(result, ndigits)
            else:
                result += 1 # same as 10 ** -0 for precision of zero digits
        return result
    
    assert round_up(0.022499999999999999, 2) == 0.03
    assert round_up(0.1111111111111000, 2) == 0.12
    
    assert round_up(1.11, 2) == 1.11
    assert round_up(1e308, 2) == 1e308
    

    【讨论】:

    • 你应该在你的代码中添加 cmets 来描述你做了什么
    • 这样更好吗?
    【解决方案9】:

    python round 函数的舍入方式可能与您预期的不同。

    您可以使用Decimal.quantize更具体地了解舍入方法

    例如。

    from decimal import Decimal, ROUND_HALF_UP
    res = Decimal('0.25').quantize(Decimal('0.0'), rounding=ROUND_HALF_UP)
    print(res) 
    # prints 0.3
    

    更多参考:

    https://gist.github.com/jackiekazil/6201722

    【讨论】:

      【解决方案10】:

      这是我在其他答案中看不到的一种简单方法。

      四舍五入到小数点后第二位:

      >>> n = 0.022499999999999999
      >>> 
      >>> -(-n//.01) * .01
      0.03
      >>> 
      

      其他价值:

      >>> n = 0.1111111111111000
      >>> 
      >>> -(-n//.01) * .01
      0.12
      >>> 
      

      对于浮点数,偶尔会出现一些不精确的值,例如,如果您要显示这些值,可以对其进行更正:

      >>> n = 10.1111111111111000
      >>> 
      >>> -(-n//0.01) * 0.01
      10.120000000000001
      >>> 
      >>> f"{-(-n//0.01) * 0.01:.2f}"
      '10.12'
      >>> 
      

      一个简单的综合函数,带有一个指定精度的参数:

      >>> roundup = lambda n, p: -(-n//10**-p) * 10**-p
      >>> 
      >>> # Or if you want to ensure truncation using the f-string method:
      >>> roundup = lambda n, p: float(f"{-(-n//10**-p) * 10**-p:.{p}f}")
      >>> 
      >>> roundup(0.111111111, 2)
      0.12
      >>> roundup(0.111111111, 3)
      0.112
      

      【讨论】:

        【解决方案11】:

        所述的圆形函数不适用于确定的整数,例如:

        a=8
        圆形(a,3)
        8.0
        a=8.00
        圆形(a,3)
        8.0
        a=8.000000000000000000000000
        圆形(a,3)
        8.0

        但是,适用于:

        r=400/3.0
        r
        133.33333333333334
        圆形(r,3)
        133.333

        此外,像 2.675 这样的小数会被四舍五入为 2.67 而不是 2.68。
        最好使用上面提供的其他方法。

        【讨论】:

        • 这不是答案,而是评论。请将此作为评论添加到相关答案中
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多