标签归档:rounding

Python 3.x舍入行为

问题:Python 3.x舍入行为

我只是在重新阅读Python 3.0的新增功能,它指出:

round()函数的舍入策略和返回类型已更改。现在,精确的中途案例将舍入到最接近的偶数结果,而不是从零舍入。(例如,round(2.5)现在返回2而不是3。)

以及关于round的文档:

对于支持round()的内置类型,将值四舍五入为乘幂n的最接近10的倍数;如果两个倍数相等接近,则四舍五入取整为偶数选择

因此,在v2.7.3下:

In [85]: round(2.5)
Out[85]: 3.0

In [86]: round(3.5)
Out[86]: 4.0

如我所料 但是,现在在v3.2.3下:

In [32]: round(2.5)
Out[32]: 2

In [33]: round(3.5)
Out[33]: 4

这似乎是违反直觉的,与我对四舍五入(并可能绊倒人)的理解相反。英语不是我的母语,但是直到我读了这篇文章,我才认为我知道四舍五入的含义:-/我确定在引入v3时一定对此进行了一些讨论,但我找不到很好的理由。我的搜索。

  1. 有人知道为什么将其更改为此吗?
  2. 是否有其他主流编程语言(例如C,C ++,Java,Perl等)进行这种(对我来说是不一致的)舍入?

我在这里想念什么?

更新:@ Li-aungYip的评论有关“银行取整”为我提供了正确的搜索词/关键字进行搜索,我发现了这样一个问题:为什么.NET默认使用银行取整?,所以我会仔细阅读。

I was just re-reading What’s New In Python 3.0 and it states:

The round() function rounding strategy and return type have changed. Exact halfway cases are now rounded to the nearest even result instead of away from zero. (For example, round(2.5) now returns 2 rather than 3.)

and the documentation for round:

For the built-in types supporting round(), values are rounded to the closest multiple of 10 to the power minus n; if two multiples are equally close, rounding is done toward the even choice

So, under v2.7.3:

In [85]: round(2.5)
Out[85]: 3.0

In [86]: round(3.5)
Out[86]: 4.0

as I’d have expected. However, now under v3.2.3:

In [32]: round(2.5)
Out[32]: 2

In [33]: round(3.5)
Out[33]: 4

This seems counter-intuitive and contrary to what I understand about rounding (and bound to trip up people). English isn’t my native language but until I read this I thought I knew what rounding meant :-/ I am sure at the time v3 was introduced there must have been some discussion of this, but I was unable to find a good reason in my search.

  1. Does anyone have insight into why this was changed to this?
  2. Are there any other mainstream programming languages (e.g., C, C++, Java, Perl, ..) that do this sort of (to me inconsistent) rounding?

What am I missing here?

UPDATE: @Li-aungYip’s comment re “Banker’s rounding” gave me the right search term/keywords to search for and I found this SO question: Why does .NET use banker’s rounding as default?, so I will be reading that carefully.


回答 0

如今,Python 3.0的方法被认为是标准的舍入方法,尽管某些语言实现尚未上市。

简单的“总是向上取整0.5”技术会导致对较高数字的轻微偏向。通过大量计算,这可能很重要。Python 3.0方法消除了这个问题。

常用的舍入方法不止一种。浮点数学的国际标准IEEE 754定义了五种不同的舍入方法(Python 3.0使用的是默认的一种)。还有其他。

这种行为并未得到应有的广泛了解。如果我没记错的话,AppleScript是这种舍入方法的早期采用者。roundAppleScript中的命令实际上确实提供了几个选项,但是IEEE 754中的默认设置是roundtoward-even round。他实现的“学校”:round 2.5 rounding as taught in school是有效的AppleScript命令。:-)

Python 3’s way (called “round half to even” or “banker’s rounding”) is considered the standard rounding method these days, though some language implementations aren’t on the bus yet.

The simple “always round 0.5 up” technique results in a slight bias toward the higher number. With large numbers of calculations, this can be significant. The Python 3.0 approach eliminates this issue.

There is more than one method of rounding in common use. IEEE 754, the international standard for floating-point math, defines five different rounding methods (the one used by Python 3.0 is the default). And there are others.

This behavior is not as widely known as it ought to be. AppleScript was, if I remember correctly, an early adopter of this rounding method. The round command in AppleScript offers several options, but round-toward-even is the default as it is in IEEE 754. Apparently the engineer who implemented the round command got so fed up with all the requests to “make it work like I learned in school” that he implemented just that: round 2.5 rounding as taught in school is a valid AppleScript command. 🙂


将浮点数向下舍入到最接近的整数?

问题:将浮点数向下舍入到最接近的整数?

如标题所示,我想取一个浮点数并将其四舍五入为最接近的整数。但是,如果它不是一个整数,那么我总是想舍入该变量,而不管它与下一个整数有多接近。有没有办法做到这一点?

As the title suggests, I want to take a floating point number and round it down to the nearest integer. However, if it’s not a whole, I ALWAYS want to round down the variable, regardless of how close it is to the next integer up. Is there a way to do this?


回答 0

简单

print int(x)

也会工作。

Simple

print int(x)

will work as well.


回答 1

其中之一应起作用:

import math
math.trunc(1.5)
> 1
math.trunc(-1.5)
> -1
math.floor(1.5)
> 1
math.floor(-1.5)
> -2

One of these should work:

import math
math.trunc(1.5)
> 1
math.trunc(-1.5)
> -1
math.floor(1.5)
> 1
math.floor(-1.5)
> -2

回答 2

x//1

//运算符返回师的地板上。由于除以1不会更改您的数字,所以这等于下限,但不需要导入。笔记:

  1. 这将返回一个浮点数
  2. 向-∞取整
x//1

The // operator returns the floor of the division. Since dividing by 1 doesn’t change your number, this is equivalent to floor but no import is needed. Notes:

  1. This returns a float
  2. This rounds towards -∞

回答 3

要获取浮点结果,只需使用:

round(x-0.5)

它也适用于负数。

To get floating point result simply use:

round(x-0.5)

It works for negative numbers as well.


回答 4

我认为您需要一个下限功能:

math.floor(x)

I think you need a floor function :

math.floor(x)


回答 5

很多人说可以使用int(x),并且在大多数情况下都可以使用,但是存在一些问题。如果OP的结果是:

x = 1.9999999999999999

它会四舍五入

x = 2

9月16日之后,它会四舍五入。如果您确定您永远不会遇到这种事情,那么这并不是什么大不了的事情。但这是要牢记的。

a lot of people say to use int(x), and this works ok for most cases, but there is a little problem. If OP’s result is:

x = 1.9999999999999999

it will round to

x = 2

after the 16th 9 it will round. This is not a big deal if you are sure you will never come across such thing. But it’s something to keep in mind.


回答 6

如果您不想导入数学,则可以使用:

int(round(x))

这是一个文档:

>>> help(round)
Help on built-in function round in module __builtin__:

round(...)
    round(number[, ndigits]) -> floating point number

    Round a number to a given precision in decimal digits (default 0 digits).
    This always returns a floating point number.  Precision may be negative.

If you don’t want to import math, you could use:

int(round(x))

Here’s a piece of documentation:

>>> help(round)
Help on built-in function round in module __builtin__:

round(...)
    round(number[, ndigits]) -> floating point number

    Round a number to a given precision in decimal digits (default 0 digits).
    This always returns a floating point number.  Precision may be negative.

回答 7

如果您使用numpy,则可以使用以下解决方案,该解决方案也适用于负数(它也适用于数组)

import numpy as np
def round_down(num):
    if num < 0:
        return -np.ceil(abs(num))
    else:
        return np.int32(num)
round_down = np.vectorize(round_down)

round_down([-1.1, -1.5, -1.6, 0, 1.1, 1.5, 1.6])
> array([-2., -2., -2.,  0.,  1.,  1.,  1.])

我认为如果仅使用math模块而不是numpy模块,它也将起作用。

If you working with numpy, you can use the following solution which also works with negative numbers (it’s also working on arrays)

import numpy as np
def round_down(num):
    if num < 0:
        return -np.ceil(abs(num))
    else:
        return np.int32(num)
round_down = np.vectorize(round_down)

round_down([-1.1, -1.5, -1.6, 0, 1.1, 1.5, 1.6])
> array([-2., -2., -2.,  0.,  1.,  1.,  1.])

I think it will also work if you just use the math module instead of numpy module.


回答 8

不知道您是否解决了这个问题,但我偶然发现了这个问题。如果要去除小数点,可以使用int(x),它将消除所有十进制数字。无需使用round(x)。

Don’t know if you solved this, but I just stumble upon this question. If you want to get rid of decimal points, you could use int(x) and it will eliminate all decimal digits. Theres no need to use round(x).


回答 9

只需取整(x-0.5),这将始终返回您的Float的下一个四舍五入的Integer值。您也可以通过do round(x + 0.5)轻松地四舍五入

Just make round(x-0.5) this will always return the next rounded down Integer value of your Float. You can also easily round up by do round(x+0.5)


回答 10

这可能很简单,但是您难道不可以将其舍去然后减去1吗?例如:

number=1.5
round(number)-1
> 1

It may be very simple, but couldn’t you just round it up then minus 1? For example:

number=1.5
round(number)-1
> 1

回答 11

我用此代码从数字中减去0.5,然后将其四舍五入,即原始数字四舍五入。

圆(a-0.5)

I used this code where you subtract 0.5 from the number and when you round it, it is the original number rounded down.

round(a-0.5)


round()似乎无法正确舍入

问题:round()似乎无法正确舍入

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

n = 5.59
round(n, 1) # 5.6

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

5.5999999999999996

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

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

The documentation for the round() function states that you pass it a number, and the positions past the decimal to round. Thus it should do this:

n = 5.59
round(n, 1) # 5.6

But, in actuality, good old floating point weirdness creeps in and you get:

5.5999999999999996

For the purposes of UI, I need to display 5.6. I poked around the Internet and found some documentation that this is dependent on my implementation of Python. Unfortunately, this occurs on both my Windows dev machine and each Linux server I’ve tried. See here also.

Short of creating my own round library, is there any way around this?


回答 0

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

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

I can’t help the way it’s stored, but at least formatting works correctly:

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

回答 1

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

"%.1f" % n

Formatting works correctly even without having to round:

"%.1f" % n

回答 2

如果使用小数模块,则无需使用“舍入”功能就可以近似。这是我用于舍入的内容,尤其是在编写货币应用程序时:

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

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

If you use the Decimal module you can approximate without the use of the ’round’ function. Here is what I’ve been using for rounding especially when writing monetary applications:

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

This will return a Decimal Number which is 16.20.


回答 3

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

>>> 5.6
5.5999999999999996
>>> 

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

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

round(5.59, 1) is working fine. The problem is that 5.6 cannot be represented exactly in binary floating point.

>>> 5.6
5.5999999999999996
>>> 

As Vinko says, you can use string formatting to do rounding for display.

Python has a module for decimal arithmetic if you need that.


回答 4

如果您执行此操作,str(round(n, 1))而不是,则会得到“ 5.6” round(n, 1)

You get ‘5.6’ if you do str(round(n, 1)) instead of just round(n, 1).


回答 5

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

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

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

但是,吉米的答案更好。

You can switch the data type to an integer:

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

And then display the number by inserting the locale’s decimal separator.

However, Jimmy’s answer is better.


回答 6

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

Floating point math is vulnerable to slight, but annoying, precision inaccuracies. If you can work with integer or fixed point, you will be guaranteed precision.


回答 7

看一下Decimal模块

十进制“基于浮点模型,该浮点模型是为人而设计的,并且必然具有最重要的指导原则–计算机必须提供一种与人们在学校学习的算法相同的算法。” –摘自十进制算术规范。

小数可以精确表示。相反,像1.1和2.2这样的数字在二进制浮点数中没有确切的表示形式。最终用户通常不会期望1.1 + 2.2像二进制浮点那样显示为3.3000000000000003。

Decimal提供了一种操作,使编写需要浮点运算的应用程序变得容易,并且需要以人类可读的格式(例如记帐)显示这些结果。

Take a look at the Decimal module

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.

and

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 provides the kind of operations that make it easy to write apps that require floating point operations and also need to present those results in a human readable format, e.g., accounting.


回答 8

打印吸盘。

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

printf the sucker.

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

回答 9

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

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的幂的分数的最接近有限和。

It’s a big problem indeed. Try out this code:

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

It displays 4.85. Then you do:

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

and it shows 4.8. Do you calculations by hand the exact answer is 4.85, but if you try:

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

you can see the truth: the float point is stored as the nearest finite sum of fractions whose denominators are powers of two.


回答 10

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

mystring = "%.2f" % 5.5999

You can use the string format operator %, similar to sprintf.

mystring = "%.2f" % 5.5999

回答 11

完美的作品

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

Works Perfect

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

回答 12

我在做:

int(round( x , 0))

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

所以

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

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

I am doing:

int(round( x , 0))

In this case, we first round properly at the unit level, then we convert to integer to avoid printing a float.

so

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

I think this answer works better than formating the string, and it also makes more sens to me to use the round function.


回答 13

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

希望有帮助。

I would avoid relying on round() at all in this case. Consider

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

will output

61.3
1.29

which is not a desired output if you need solid rounding to the nearest integer. To bypass this behavior go with math.ceil() (or math.floor() if you want to round down):

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)

outputs

61.3
1.3

Hope that helps.


回答 14

码:

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

Code:

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'

Output:

5.6
5.7

回答 15

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

Here’s where I see round failing. What if you wanted to round these 2 numbers to one decimal place? 23.45 23.55 My education was that from rounding these you should get: 23.4 23.6 the “rule” being that you should round up if the preceding number was odd, not round up if the preceding number were even. The round function in python simply truncates the 5.


回答 16

问题仅在最后一位数字为5时出现。0.045在内部存储为0.044999999999999 …您可以将最后一位数字简单地增加到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

The problem is only when last digit is 5. Eg. 0.045 is internally stored as 0.044999999999999… You could simply increment last digit to 6 and round off. This will give you the desired results.

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

回答 17

另一个可能的选择是:

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)

Another potential option is:

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)

回答 18

关于什么:

round(n,1)+epsilon

What about:

round(n,1)+epsilon

如何舍入日期时间对象的分钟

问题:如何舍入日期时间对象的分钟

I have a datetime object produced using strptime()。

>>> tm
datetime.datetime(2010, 6, 10, 3, 56, 23)

我需要做的是将分钟调整为最接近的第10分钟。到目前为止,我一直在做分钟值并在其上使用round()。

min = round(tm.minute, -1)

但是,与上面的示例一样,当分钟值大于56时,它将给出无效的时间。即:3:60

有什么更好的方法可以做到这一点?是否datetime支持?

I have a datetime object produced using strptime().

>>> tm
datetime.datetime(2010, 6, 10, 3, 56, 23)

What I need to do is round the minute to the closest 10th minute. What I have been doing up to this point was taking the minute value and using round() on it.

min = round(tm.minute, -1)

However, as with the above example, it gives an invalid time when the minute value is greater than 56. i.e.: 3:60

What is a better way to do this? Does datetime support this?


回答 0

这将使datetime存储在tm 中的对象的“底楼” 四舍五入到之前的10分钟标记tm

tm = tm - datetime.timedelta(minutes=tm.minute % 10,
                             seconds=tm.second,
                             microseconds=tm.microsecond)

如果要将经典舍入到最近的10分钟标记,请执行以下操作:

discard = datetime.timedelta(minutes=tm.minute % 10,
                             seconds=tm.second,
                             microseconds=tm.microsecond)
tm -= discard
if discard >= datetime.timedelta(minutes=5):
    tm += datetime.timedelta(minutes=10)

或这个:

tm += datetime.timedelta(minutes=5)
tm -= datetime.timedelta(minutes=tm.minute % 10,
                         seconds=tm.second,
                         microseconds=tm.microsecond)

This will get the ‘floor’ of a datetime object stored in tm rounded to the 10 minute mark before tm.

tm = tm - datetime.timedelta(minutes=tm.minute % 10,
                             seconds=tm.second,
                             microseconds=tm.microsecond)

If you want classic rounding to the nearest 10 minute mark, do this:

discard = datetime.timedelta(minutes=tm.minute % 10,
                             seconds=tm.second,
                             microseconds=tm.microsecond)
tm -= discard
if discard >= datetime.timedelta(minutes=5):
    tm += datetime.timedelta(minutes=10)

or this:

tm += datetime.timedelta(minutes=5)
tm -= datetime.timedelta(minutes=tm.minute % 10,
                         seconds=tm.second,
                         microseconds=tm.microsecond)

回答 1

用于舍入日期时间的通用功能,以秒为单位:

def roundTime(dt=None, roundTo=60):
   """Round a datetime object to any time lapse in seconds
   dt : datetime.datetime object, default now.
   roundTo : Closest number of seconds to round to, default 1 minute.
   Author: Thierry Husson 2012 - Use it as you want but don't blame me.
   """
   if dt == None : dt = datetime.datetime.now()
   seconds = (dt.replace(tzinfo=None) - dt.min).seconds
   rounding = (seconds+roundTo/2) // roundTo * roundTo
   return dt + datetime.timedelta(0,rounding-seconds,-dt.microsecond)

四舍五入1小时和30分钟四舍五入的样本:

print roundTime(datetime.datetime(2012,12,31,23,44,59,1234),roundTo=60*60)
2013-01-01 00:00:00

print roundTime(datetime.datetime(2012,12,31,23,44,59,1234),roundTo=30*60)
2012-12-31 23:30:00

General function to round a datetime at any time lapse in seconds:

def roundTime(dt=None, roundTo=60):
   """Round a datetime object to any time lapse in seconds
   dt : datetime.datetime object, default now.
   roundTo : Closest number of seconds to round to, default 1 minute.
   Author: Thierry Husson 2012 - Use it as you want but don't blame me.
   """
   if dt == None : dt = datetime.datetime.now()
   seconds = (dt.replace(tzinfo=None) - dt.min).seconds
   rounding = (seconds+roundTo/2) // roundTo * roundTo
   return dt + datetime.timedelta(0,rounding-seconds,-dt.microsecond)

Samples with 1 hour rounding & 30 minutes rounding:

print roundTime(datetime.datetime(2012,12,31,23,44,59,1234),roundTo=60*60)
2013-01-01 00:00:00

print roundTime(datetime.datetime(2012,12,31,23,44,59,1234),roundTo=30*60)
2012-12-31 23:30:00

回答 2

从最好的答案我修改为仅使用datetime对象的版本,这避免了必须转换为秒的情况,并使调用代码更具可读性:

def roundTime(dt=None, dateDelta=datetime.timedelta(minutes=1)):
    """Round a datetime object to a multiple of a timedelta
    dt : datetime.datetime object, default now.
    dateDelta : timedelta object, we round to a multiple of this, default 1 minute.
    Author: Thierry Husson 2012 - Use it as you want but don't blame me.
            Stijn Nevens 2014 - Changed to use only datetime objects as variables
    """
    roundTo = dateDelta.total_seconds()

    if dt == None : dt = datetime.datetime.now()
    seconds = (dt - dt.min).seconds
    # // is a floor division, not a comment on following line:
    rounding = (seconds+roundTo/2) // roundTo * roundTo
    return dt + datetime.timedelta(0,rounding-seconds,-dt.microsecond)

四舍五入1小时和15分钟四舍五入的样本:

print roundTime(datetime.datetime(2012,12,31,23,44,59),datetime.timedelta(hour=1))
2013-01-01 00:00:00

print roundTime(datetime.datetime(2012,12,31,23,44,49),datetime.timedelta(minutes=15))
2012-12-31 23:30:00

From the best answer I modified to an adapted version using only datetime objects, this avoids having to do the conversion to seconds and makes the calling code more readable:

def roundTime(dt=None, dateDelta=datetime.timedelta(minutes=1)):
    """Round a datetime object to a multiple of a timedelta
    dt : datetime.datetime object, default now.
    dateDelta : timedelta object, we round to a multiple of this, default 1 minute.
    Author: Thierry Husson 2012 - Use it as you want but don't blame me.
            Stijn Nevens 2014 - Changed to use only datetime objects as variables
    """
    roundTo = dateDelta.total_seconds()

    if dt == None : dt = datetime.datetime.now()
    seconds = (dt - dt.min).seconds
    # // is a floor division, not a comment on following line:
    rounding = (seconds+roundTo/2) // roundTo * roundTo
    return dt + datetime.timedelta(0,rounding-seconds,-dt.microsecond)

Samples with 1 hour rounding & 15 minutes rounding:

print roundTime(datetime.datetime(2012,12,31,23,44,59),datetime.timedelta(hour=1))
2013-01-01 00:00:00

print roundTime(datetime.datetime(2012,12,31,23,44,49),datetime.timedelta(minutes=15))
2012-12-31 23:30:00

回答 3

我使用了Stijn Nevens代码(谢谢Stijn),并且有一些共享的附件。向上,向下取整并四舍五入到最接近的值。

更新2019-03-09 =评论并入Spinxz; 谢谢。

更新2019-12-27 =评论Bart纳入; 谢谢。

测试了“ X小时”或“ X分钟”或“ X秒”的date_delta。

import datetime

def round_time(dt=None, date_delta=datetime.timedelta(minutes=1), to='average'):
    """
    Round a datetime object to a multiple of a timedelta
    dt : datetime.datetime object, default now.
    dateDelta : timedelta object, we round to a multiple of this, default 1 minute.
    from:  http://stackoverflow.com/questions/3463930/how-to-round-the-minute-of-a-datetime-object-python
    """
    round_to = date_delta.total_seconds()
    if dt is None:
        dt = datetime.now()
    seconds = (dt - dt.min).seconds

    if seconds % round_to == 0 and dt.microsecond == 0:
        rounding = (seconds + round_to / 2) // round_to * round_to
    else:
        if to == 'up':
            # // is a floor division, not a comment on following line (like in javascript):
            rounding = (seconds + dt.microsecond/1000000 + round_to) // round_to * round_to
        elif to == 'down':
            rounding = seconds // round_to * round_to
        else:
            rounding = (seconds + round_to / 2) // round_to * round_to

    return dt + datetime.timedelta(0, rounding - seconds, - dt.microsecond)

# test data
print(round_time(datetime.datetime(2019,11,1,14,39,00), date_delta=datetime.timedelta(seconds=30), to='up'))
print(round_time(datetime.datetime(2019,11,2,14,39,00,1), date_delta=datetime.timedelta(seconds=30), to='up'))
print(round_time(datetime.datetime(2019,11,3,14,39,00,776980), date_delta=datetime.timedelta(seconds=30), to='up'))
print(round_time(datetime.datetime(2019,11,4,14,39,29,776980), date_delta=datetime.timedelta(seconds=30), to='up'))
print(round_time(datetime.datetime(2018,11,5,14,39,00,776980), date_delta=datetime.timedelta(seconds=30), to='down'))
print(round_time(datetime.datetime(2018,11,6,14,38,59,776980), date_delta=datetime.timedelta(seconds=30), to='down'))
print(round_time(datetime.datetime(2017,11,7,14,39,15), date_delta=datetime.timedelta(seconds=30), to='average'))
print(round_time(datetime.datetime(2017,11,8,14,39,14,999999), date_delta=datetime.timedelta(seconds=30), to='average'))
print(round_time(datetime.datetime(2019,11,9,14,39,14,999999), date_delta=datetime.timedelta(seconds=30), to='up'))
print(round_time(datetime.datetime(2012,12,10,23,44,59,7769),to='average'))
print(round_time(datetime.datetime(2012,12,11,23,44,59,7769),to='up'))
print(round_time(datetime.datetime(2010,12,12,23,44,59,7769),to='down',date_delta=datetime.timedelta(seconds=1)))
print(round_time(datetime.datetime(2011,12,13,23,44,59,7769),to='up',date_delta=datetime.timedelta(seconds=1)))
print(round_time(datetime.datetime(2012,12,14,23,44,59),date_delta=datetime.timedelta(hours=1),to='down'))
print(round_time(datetime.datetime(2012,12,15,23,44,59),date_delta=datetime.timedelta(hours=1),to='up'))
print(round_time(datetime.datetime(2012,12,16,23,44,59),date_delta=datetime.timedelta(hours=1)))
print(round_time(datetime.datetime(2012,12,17,23,00,00),date_delta=datetime.timedelta(hours=1),to='down'))
print(round_time(datetime.datetime(2012,12,18,23,00,00),date_delta=datetime.timedelta(hours=1),to='up'))
print(round_time(datetime.datetime(2012,12,19,23,00,00),date_delta=datetime.timedelta(hours=1)))

I used Stijn Nevens code (thank you Stijn) and have a little add-on to share. Rounding up, down and rounding to nearest.

update 2019-03-09 = comment Spinxz incorporated; thank you.

update 2019-12-27 = comment Bart incorporated; thank you.

Tested for date_delta of “X hours” or “X minutes” or “X seconds”.

import datetime

def round_time(dt=None, date_delta=datetime.timedelta(minutes=1), to='average'):
    """
    Round a datetime object to a multiple of a timedelta
    dt : datetime.datetime object, default now.
    dateDelta : timedelta object, we round to a multiple of this, default 1 minute.
    from:  http://stackoverflow.com/questions/3463930/how-to-round-the-minute-of-a-datetime-object-python
    """
    round_to = date_delta.total_seconds()
    if dt is None:
        dt = datetime.now()
    seconds = (dt - dt.min).seconds

    if seconds % round_to == 0 and dt.microsecond == 0:
        rounding = (seconds + round_to / 2) // round_to * round_to
    else:
        if to == 'up':
            # // is a floor division, not a comment on following line (like in javascript):
            rounding = (seconds + dt.microsecond/1000000 + round_to) // round_to * round_to
        elif to == 'down':
            rounding = seconds // round_to * round_to
        else:
            rounding = (seconds + round_to / 2) // round_to * round_to

    return dt + datetime.timedelta(0, rounding - seconds, - dt.microsecond)

# test data
print(round_time(datetime.datetime(2019,11,1,14,39,00), date_delta=datetime.timedelta(seconds=30), to='up'))
print(round_time(datetime.datetime(2019,11,2,14,39,00,1), date_delta=datetime.timedelta(seconds=30), to='up'))
print(round_time(datetime.datetime(2019,11,3,14,39,00,776980), date_delta=datetime.timedelta(seconds=30), to='up'))
print(round_time(datetime.datetime(2019,11,4,14,39,29,776980), date_delta=datetime.timedelta(seconds=30), to='up'))
print(round_time(datetime.datetime(2018,11,5,14,39,00,776980), date_delta=datetime.timedelta(seconds=30), to='down'))
print(round_time(datetime.datetime(2018,11,6,14,38,59,776980), date_delta=datetime.timedelta(seconds=30), to='down'))
print(round_time(datetime.datetime(2017,11,7,14,39,15), date_delta=datetime.timedelta(seconds=30), to='average'))
print(round_time(datetime.datetime(2017,11,8,14,39,14,999999), date_delta=datetime.timedelta(seconds=30), to='average'))
print(round_time(datetime.datetime(2019,11,9,14,39,14,999999), date_delta=datetime.timedelta(seconds=30), to='up'))
print(round_time(datetime.datetime(2012,12,10,23,44,59,7769),to='average'))
print(round_time(datetime.datetime(2012,12,11,23,44,59,7769),to='up'))
print(round_time(datetime.datetime(2010,12,12,23,44,59,7769),to='down',date_delta=datetime.timedelta(seconds=1)))
print(round_time(datetime.datetime(2011,12,13,23,44,59,7769),to='up',date_delta=datetime.timedelta(seconds=1)))
print(round_time(datetime.datetime(2012,12,14,23,44,59),date_delta=datetime.timedelta(hours=1),to='down'))
print(round_time(datetime.datetime(2012,12,15,23,44,59),date_delta=datetime.timedelta(hours=1),to='up'))
print(round_time(datetime.datetime(2012,12,16,23,44,59),date_delta=datetime.timedelta(hours=1)))
print(round_time(datetime.datetime(2012,12,17,23,00,00),date_delta=datetime.timedelta(hours=1),to='down'))
print(round_time(datetime.datetime(2012,12,18,23,00,00),date_delta=datetime.timedelta(hours=1),to='up'))
print(round_time(datetime.datetime(2012,12,19,23,00,00),date_delta=datetime.timedelta(hours=1)))

回答 4

Pandas具有日期时间取整功能,但与Pandas中的大多数其他功能一样,它必须采用Series格式。

>>> ts = pd.Series(pd.date_range(Dt(2019,1,1,1,1),Dt(2019,1,1,1,4),periods=8))
>>> print(ts)
0   2019-01-01 01:01:00.000000000
1   2019-01-01 01:01:25.714285714
2   2019-01-01 01:01:51.428571428
3   2019-01-01 01:02:17.142857142
4   2019-01-01 01:02:42.857142857
5   2019-01-01 01:03:08.571428571
6   2019-01-01 01:03:34.285714285
7   2019-01-01 01:04:00.000000000
dtype: datetime64[ns]

>>> ts.dt.round('1min')
0   2019-01-01 01:01:00
1   2019-01-01 01:01:00
2   2019-01-01 01:02:00
3   2019-01-01 01:02:00
4   2019-01-01 01:03:00
5   2019-01-01 01:03:00
6   2019-01-01 01:04:00
7   2019-01-01 01:04:00
dtype: datetime64[ns]

文档 -根据需要更改频率字符串。

Pandas has a datetime round feature, but as with most things in Pandas it needs to be in Series format.

>>> ts = pd.Series(pd.date_range(Dt(2019,1,1,1,1),Dt(2019,1,1,1,4),periods=8))
>>> print(ts)
0   2019-01-01 01:01:00.000000000
1   2019-01-01 01:01:25.714285714
2   2019-01-01 01:01:51.428571428
3   2019-01-01 01:02:17.142857142
4   2019-01-01 01:02:42.857142857
5   2019-01-01 01:03:08.571428571
6   2019-01-01 01:03:34.285714285
7   2019-01-01 01:04:00.000000000
dtype: datetime64[ns]

>>> ts.dt.round('1min')
0   2019-01-01 01:01:00
1   2019-01-01 01:01:00
2   2019-01-01 01:02:00
3   2019-01-01 01:02:00
4   2019-01-01 01:03:00
5   2019-01-01 01:03:00
6   2019-01-01 01:04:00
7   2019-01-01 01:04:00
dtype: datetime64[ns]

Docs – Change the frequency string as needed.


回答 5

如果您不想使用条件,则可以使用modulo运算符:

minutes = int(round(tm.minute, -1)) % 60

更新

你想要这样的东西吗?

def timeround10(dt):
    a, b = divmod(round(dt.minute, -1), 60)
    return '%i:%02i' % ((dt.hour + a) % 24, b)

timeround10(datetime.datetime(2010, 1, 1, 0, 56, 0)) # 0:56
# -> 1:00

timeround10(datetime.datetime(2010, 1, 1, 23, 56, 0)) # 23:56
# -> 0:00

..如果要将结果作为字符串。为了获得日期时间结果,最好使用timedelta-参见其他响应;)

if you don’t want to use condition, you can use modulo operator:

minutes = int(round(tm.minute, -1)) % 60

UPDATE

did you want something like this?

def timeround10(dt):
    a, b = divmod(round(dt.minute, -1), 60)
    return '%i:%02i' % ((dt.hour + a) % 24, b)

timeround10(datetime.datetime(2010, 1, 1, 0, 56, 0)) # 0:56
# -> 1:00

timeround10(datetime.datetime(2010, 1, 1, 23, 56, 0)) # 23:56
# -> 0:00

.. if you want result as string. for obtaining datetime result, it’s better to use timedelta – see other responses 😉


回答 6

我正在用这个。它具有使用tz知道的日期时间的优势。

def round_minutes(some_datetime: datetime, step: int):
    """ round up to nearest step-minutes """
    if step > 60:
        raise AttrbuteError("step must be less than 60")

    change = timedelta(
        minutes= some_datetime.minute % step,
        seconds=some_datetime.second,
        microseconds=some_datetime.microsecond
    )

    if change > timedelta():
        change -= timedelta(minutes=step)

    return some_datetime - change

它的缺点是只能为时间片工作少于一个小时。

i’m using this. it has the advantage of working with tz aware datetimes.

def round_minutes(some_datetime: datetime, step: int):
    """ round up to nearest step-minutes """
    if step > 60:
        raise AttrbuteError("step must be less than 60")

    change = timedelta(
        minutes= some_datetime.minute % step,
        seconds=some_datetime.second,
        microseconds=some_datetime.microsecond
    )

    if change > timedelta():
        change -= timedelta(minutes=step)

    return some_datetime - change

it has the disadvantage of only working for timeslices less than an hour.


回答 7

这是一个更简单的通用解决方案,没有浮点精度问题和外部库依赖性:

import datetime as dt

def time_mod(time, delta, epoch=None):
    if epoch is None:
        epoch = dt.datetime(1970, 1, 1, tzinfo=time.tzinfo)
    return (time - epoch) % delta

def time_round(time, delta, epoch=None):
    mod = time_mod(time, delta, epoch)
    if mod < (delta / 2):
       return time - mod
    return time + (delta - mod)

在您的情况下:

>>> tm
datetime.datetime(2010, 6, 10, 3, 56, 23)
>>> time_round(tm, dt.timedelta(minutes=10))
datetime.datetime(2010, 6, 10, 4, 0)

Here is a simpler generalized solution without floating point precision issues and external library dependencies:

import datetime

def time_mod(time, delta, epoch=None):
    if epoch is None:
        epoch = datetime.datetime(1970, 1, 1, tzinfo=time.tzinfo)
    return (time - epoch) % delta

def time_round(time, delta, epoch=None):
    mod = time_mod(time, delta, epoch)
    if mod < (delta / 2):
       return time - mod
    return time + (delta - mod)

In your case:

>>> tm = datetime.datetime(2010, 6, 10, 3, 56, 23)
>>> time_round(tm, datetime.timedelta(minutes=10))
datetime.datetime(2010, 6, 10, 4, 0)

回答 8

def get_rounded_datetime(self, dt, freq, nearest_type='inf'):

    if freq.lower() == '1h':
        round_to = 3600
    elif freq.lower() == '3h':
        round_to = 3 * 3600
    elif freq.lower() == '6h':
        round_to = 6 * 3600
    else:
        raise NotImplementedError("Freq %s is not handled yet" % freq)

    # // is a floor division, not a comment on following line:
    seconds_from_midnight = dt.hour * 3600 + dt.minute * 60 + dt.second
    if nearest_type == 'inf':
        rounded_sec = int(seconds_from_midnight / round_to) * round_to
    elif nearest_type == 'sup':
        rounded_sec = (int(seconds_from_midnight / round_to) + 1) * round_to
    else:
        raise IllegalArgumentException("nearest_type should be  'inf' or 'sup'")

    dt_midnight = datetime.datetime(dt.year, dt.month, dt.day)

    return dt_midnight + datetime.timedelta(0, rounded_sec)
def get_rounded_datetime(self, dt, freq, nearest_type='inf'):

    if freq.lower() == '1h':
        round_to = 3600
    elif freq.lower() == '3h':
        round_to = 3 * 3600
    elif freq.lower() == '6h':
        round_to = 6 * 3600
    else:
        raise NotImplementedError("Freq %s is not handled yet" % freq)

    # // is a floor division, not a comment on following line:
    seconds_from_midnight = dt.hour * 3600 + dt.minute * 60 + dt.second
    if nearest_type == 'inf':
        rounded_sec = int(seconds_from_midnight / round_to) * round_to
    elif nearest_type == 'sup':
        rounded_sec = (int(seconds_from_midnight / round_to) + 1) * round_to
    else:
        raise IllegalArgumentException("nearest_type should be  'inf' or 'sup'")

    dt_midnight = datetime.datetime(dt.year, dt.month, dt.day)

    return dt_midnight + datetime.timedelta(0, rounded_sec)

回答 9

基于Stijn Nevens并针对Django进行了修改,以将当前时间四舍五入到最近的15分钟。

from datetime import date, timedelta, datetime, time

    def roundTime(dt=None, dateDelta=timedelta(minutes=1)):

        roundTo = dateDelta.total_seconds()

        if dt == None : dt = datetime.now()
        seconds = (dt - dt.min).seconds
        # // is a floor division, not a comment on following line:
        rounding = (seconds+roundTo/2) // roundTo * roundTo
        return dt + timedelta(0,rounding-seconds,-dt.microsecond)

    dt = roundTime(datetime.now(),timedelta(minutes=15)).strftime('%H:%M:%S')

 dt = 11:45:00

如果您需要完整的日期和时间,只需删除 .strftime('%H:%M:%S')

Based on Stijn Nevens and modified for Django use to round current time to the nearest 15 minute.

from datetime import date, timedelta, datetime, time

    def roundTime(dt=None, dateDelta=timedelta(minutes=1)):

        roundTo = dateDelta.total_seconds()

        if dt == None : dt = datetime.now()
        seconds = (dt - dt.min).seconds
        # // is a floor division, not a comment on following line:
        rounding = (seconds+roundTo/2) // roundTo * roundTo
        return dt + timedelta(0,rounding-seconds,-dt.microsecond)

    dt = roundTime(datetime.now(),timedelta(minutes=15)).strftime('%H:%M:%S')

 dt = 11:45:00

if you need full date and time just remove the .strftime('%H:%M:%S')


回答 10

当捕获到异常时,不是最好的速度,但是这可以工作。

def _minute10(dt=datetime.utcnow()):
    try:
        return dt.replace(minute=round(dt.minute, -1))
    except ValueError:
        return dt.replace(minute=0) + timedelta(hours=1)

时机

%timeit _minute10(datetime(2016, 12, 31, 23, 55))
100000 loops, best of 3: 5.12 µs per loop

%timeit _minute10(datetime(2016, 12, 31, 23, 31))
100000 loops, best of 3: 2.21 µs per loop

Not the best for speed when the exception is caught, however this would work.

def _minute10(dt=datetime.utcnow()):
    try:
        return dt.replace(minute=round(dt.minute, -1))
    except ValueError:
        return dt.replace(minute=0) + timedelta(hours=1)

Timings

%timeit _minute10(datetime(2016, 12, 31, 23, 55))
100000 loops, best of 3: 5.12 µs per loop

%timeit _minute10(datetime(2016, 12, 31, 23, 31))
100000 loops, best of 3: 2.21 µs per loop

回答 11

两行直观的解决方案,用于将datetime对象舍入到给定的时间单位(此处为秒)t

format_str = '%Y-%m-%d %H:%M:%S'
t_rounded = datetime.strptime(datetime.strftime(t, format_str), format_str)

如果您想舍入到另一个单位,只需更改format_str

这种方法不能像上述方法那样四舍五入到任意时间,而是一种很好的Pythonic方法,可以四舍五入到给定的小时,分​​钟或秒。

A two line intuitive solution to round to a given time unit, here seconds, for a datetime object t:

format_str = '%Y-%m-%d %H:%M:%S'
t_rounded = datetime.strptime(datetime.strftime(t, format_str), format_str)

If you wish to round to a different unit simply alter format_str.

This approach does not round to arbitrary time amounts as above methods, but is a nicely Pythonic way to round to a given hour, minute or second.


回答 12

其他解决方案:

def round_time(timestamp=None, lapse=0):
    """
    Round a timestamp to a lapse according to specified minutes

    Usage:

    >>> import datetime, math
    >>> round_time(datetime.datetime(2010, 6, 10, 3, 56, 23), 0)
    datetime.datetime(2010, 6, 10, 3, 56)
    >>> round_time(datetime.datetime(2010, 6, 10, 3, 56, 23), 1)
    datetime.datetime(2010, 6, 10, 3, 57)
    >>> round_time(datetime.datetime(2010, 6, 10, 3, 56, 23), -1)
    datetime.datetime(2010, 6, 10, 3, 55)
    >>> round_time(datetime.datetime(2019, 3, 11, 9, 22, 11), 3)
    datetime.datetime(2019, 3, 11, 9, 24)
    >>> round_time(datetime.datetime(2019, 3, 11, 9, 22, 11), 3*60)
    datetime.datetime(2019, 3, 11, 12, 0)
    >>> round_time(datetime.datetime(2019, 3, 11, 10, 0, 0), 3)
    datetime.datetime(2019, 3, 11, 10, 0)

    :param timestamp: Timestamp to round (default: now)
    :param lapse: Lapse to round in minutes (default: 0)
    """
    t = timestamp or datetime.datetime.now()  # type: Union[datetime, Any]
    surplus = datetime.timedelta(seconds=t.second, microseconds=t.microsecond)
    t -= surplus
    try:
        mod = t.minute % lapse
    except ZeroDivisionError:
        return t
    if mod:  # minutes % lapse != 0
        t += datetime.timedelta(minutes=math.ceil(t.minute / lapse) * lapse - t.minute)
    elif surplus != datetime.timedelta() or lapse < 0:
        t += datetime.timedelta(minutes=(t.minute / lapse + 1) * lapse - t.minute)
    return t

希望这可以帮助!

Other solution:

def round_time(timestamp=None, lapse=0):
    """
    Round a timestamp to a lapse according to specified minutes

    Usage:

    >>> import datetime, math
    >>> round_time(datetime.datetime(2010, 6, 10, 3, 56, 23), 0)
    datetime.datetime(2010, 6, 10, 3, 56)
    >>> round_time(datetime.datetime(2010, 6, 10, 3, 56, 23), 1)
    datetime.datetime(2010, 6, 10, 3, 57)
    >>> round_time(datetime.datetime(2010, 6, 10, 3, 56, 23), -1)
    datetime.datetime(2010, 6, 10, 3, 55)
    >>> round_time(datetime.datetime(2019, 3, 11, 9, 22, 11), 3)
    datetime.datetime(2019, 3, 11, 9, 24)
    >>> round_time(datetime.datetime(2019, 3, 11, 9, 22, 11), 3*60)
    datetime.datetime(2019, 3, 11, 12, 0)
    >>> round_time(datetime.datetime(2019, 3, 11, 10, 0, 0), 3)
    datetime.datetime(2019, 3, 11, 10, 0)

    :param timestamp: Timestamp to round (default: now)
    :param lapse: Lapse to round in minutes (default: 0)
    """
    t = timestamp or datetime.datetime.now()  # type: Union[datetime, Any]
    surplus = datetime.timedelta(seconds=t.second, microseconds=t.microsecond)
    t -= surplus
    try:
        mod = t.minute % lapse
    except ZeroDivisionError:
        return t
    if mod:  # minutes % lapse != 0
        t += datetime.timedelta(minutes=math.ceil(t.minute / lapse) * lapse - t.minute)
    elif surplus != datetime.timedelta() or lapse < 0:
        t += datetime.timedelta(minutes=(t.minute / lapse + 1) * lapse - t.minute)
    return t

Hope this helps!


回答 13

我知道的最短方法

min = tm.minute // 10 * 10

The shortest way I know

min = tm.minute // 10 * 10


回答 14

那些看起来太复杂了

def round_down_to():
    num = int(datetime.utcnow().replace(second=0, microsecond=0).minute)
    return num - (num%10)

Those seem overly complex

def round_down_to():
    num = int(datetime.utcnow().replace(second=0, microsecond=0).minute)
    return num - (num%10)

回答 15

一种简单的方法:

def round_time(dt, round_to_seconds=60):
    """Round a datetime object to any number of seconds
    dt: datetime.datetime object
    round_to_seconds: closest number of seconds for rounding, Default 1 minute.
    """
    rounded_epoch = round(dt.timestamp() / round_to_seconds) * round_to_seconds
    rounded_dt = datetime.datetime.fromtimestamp(rounded_epoch).astimezone(dt.tzinfo)
    return rounded_dt

A straightforward approach:

def round_time(dt, round_to_seconds=60):
    """Round a datetime object to any number of seconds
    dt: datetime.datetime object
    round_to_seconds: closest number of seconds for rounding, Default 1 minute.
    """
    rounded_epoch = round(dt.timestamp() / round_to_seconds) * round_to_seconds
    rounded_dt = datetime.datetime.fromtimestamp(rounded_epoch).astimezone(dt.tzinfo)
    return rounded_dt

回答 16

是的,如果您的数据属于pandas系列中的DateTime列,则可以使用内置的pandas.Series.dt.round函数将其向上舍入。请参阅pandas.Series.dt.round上的文档。在四舍五入到10分钟的情况下,它将是Series.dt.round(’10min’)或Series.dt.round(’600s’),如下所示:

pandas.Series(tm).dt.round('10min')

编辑以添加示例代码:

import datetime
import pandas

tm = datetime.datetime(2010, 6, 10, 3, 56, 23)
tm_rounded = pandas.Series(tm).dt.round('10min')
print(tm_rounded)

>>> 0   2010-06-10 04:00:00
dtype: datetime64[ns]

yes, if your data belongs to a DateTime column in a pandas series, you can round it up using the built-in pandas.Series.dt.round function. See documentation here on pandas.Series.dt.round. In your case of rounding to 10min it will be Series.dt.round(’10min’) or Series.dt.round(‘600s’) like so:

pandas.Series(tm).dt.round('10min')

Edit to add Example code:

import datetime
import pandas

tm = datetime.datetime(2010, 6, 10, 3, 56, 23)
tm_rounded = pandas.Series(tm).dt.round('10min')
print(tm_rounded)

>>> 0   2010-06-10 04:00:00
dtype: datetime64[ns]

在Python中舍入到5(或其他数字)

问题:在Python中舍入到5(或其他数字)

是否有一个内置函数可以像下面这样四舍五入?

10 -> 10
12 -> 10
13 -> 15
14 -> 15
16 -> 15
18 -> 20

Is there a built-in function that can round like the following?

10 -> 10
12 -> 10
13 -> 15
14 -> 15
16 -> 15
18 -> 20

回答 0

我不知道Python中的标准函数,但这对我有用:

Python 2

def myround(x, base=5):
    return int(base * round(float(x)/base))

Python3

def myround(x, base=5):
    return base * round(x/base)

很容易看出上述原因。您要确保将数字除以5是一个正确四舍五入的整数。所以,我们首先做到这些(round(float(x)/5)这里float只需要在Python2),然后因为我们除以5,我们乘以5为好。最终转换为int是因为round()在Python 2中返回了浮点值。

我通过给它一个base参数(默认值为5)使该函数更通用。

I don’t know of a standard function in Python, but this works for me:

Python 2

def myround(x, base=5):
    return int(base * round(float(x)/base))

Python3

def myround(x, base=5):
    return base * round(x/base)

It is easy to see why the above works. You want to make sure that your number divided by 5 is an integer, correctly rounded. So, we first do exactly that (round(float(x)/5) where float is only needed in Python2), and then since we divided by 5, we multiply by 5 as well. The final conversion to int is because round() returns a floating-point value in Python 2.

I made the function more generic by giving it a base parameter, defaulting to 5.


回答 1

对于四舍五入为非整数值,例如0.05:

def myround(x, prec=2, base=.05):
  return round(base * round(float(x)/base),prec)

我发现这很有用,因为我可以进行搜索并替换代码,将“ round(”更改为“ myround(”),而不必更改参数值。

For rounding to non-integer values, such as 0.05:

def myround(x, prec=2, base=.05):
  return round(base * round(float(x)/base),prec)

I found this useful since I could just do a search and replace in my code to change “round(” to “myround(“, without having to change the parameter values.


回答 2

这只是扩展问题

>>> a=[10,11,12,13,14,15,16,17,18,19,20]
>>> for b in a:
...     int(round(b/5.0)*5.0)
... 
10
10
10
15
15
15
15
15
20
20
20

It’s just a matter of scaling

>>> a=[10,11,12,13,14,15,16,17,18,19,20]
>>> for b in a:
...     int(round(b/5.0)*5.0)
... 
10
10
10
15
15
15
15
15
20
20
20

回答 3

删除“其余”将起作用:

rounded = int(val) - int(val) % 5

如果值是aready,则为整数:

rounded = val - val % 5

作为功​​能:

def roundint(value, base=5):
    return int(value) - int(value) % int(base)

Removing the ‘rest’ would work:

rounded = int(val) - int(val) % 5

If the value is aready an integer:

rounded = val - val % 5

As a function:

def roundint(value, base=5):
    return int(value) - int(value) % int(base)

回答 4

def round_to_next5(n):
    return n + (5 - n) % 5
def round_to_next5(n):
    return n + (5 - n) % 5

回答 5

round(x [,n]):将值四舍五入为乘幂n的最接近10的倍数。所以如果n为负…

def round5(x):
    return int(round(x*2, -1)) / 2

由于10 = 5 * 2,您可以对2使用整数除法和乘法,而不是对5.0使用浮点除法和乘法。没关系,除非您喜欢移位

def round5(x):
    return int(round(x << 1, -1)) >> 1

round(x[, n]): values are rounded to the closest multiple of 10 to the power minus n. So if n is negative…

def round5(x):
    return int(round(x*2, -1)) / 2

Since 10 = 5 * 2, you can use integer division and multiplication with 2, rather than float division and multiplication with 5.0. Not that that matters much, unless you like bit shifting

def round5(x):
    return int(round(x << 1, -1)) >> 1

回答 6

抱歉,我想评论Alok Singhai的回答,但由于缺乏声誉而不能让我= /

无论如何,我们可以概括出另外一个步骤:

def myround(x, base=5):
    return base * round(float(x) / base)

这使我们可以使用非整数基,例如.25或任何其他小数基。

Sorry, I wanted to comment on Alok Singhai’s answer, but it won’t let me due to a lack of reputation =/

Anyway, we can generalize one more step and go:

def myround(x, base=5):
    return base * round(float(x) / base)

This allows us to use non-integer bases, like .25 or any other fractional base.


回答 7

divround的修改版本:-)

def divround(value, step, barrage):
    result, rest = divmod(value, step)
    return result*step if rest < barrage else (result+1)*step

Modified version of divround 🙂

def divround(value, step, barrage):
    result, rest = divmod(value, step)
    return result*step if rest < barrage else (result+1)*step

回答 8

用:

>>> def round_to_nearest(n, m):
        r = n % m
        return n + m - r if r + r >= m else n - r

它不使用乘法,也不会从浮点数转换为浮点数。

四舍五入到最接近的10的倍数:

>>> for n in range(-21, 30, 3): print('{:3d}  =>  {:3d}'.format(n, round_to_nearest(n, 10)))
-21  =>  -20
-18  =>  -20
-15  =>  -10
-12  =>  -10
 -9  =>  -10
 -6  =>  -10
 -3  =>    0
  0  =>    0
  3  =>    0
  6  =>   10
  9  =>   10
 12  =>   10
 15  =>   20
 18  =>   20
 21  =>   20
 24  =>   20
 27  =>   30

如您所见,它适用于负数和正数。领带(例如-15和15)将始终向上舍入。

将四舍五入到最接近的5的倍数的类似示例,表明它的行为也与其他“底数”相同:

>>> for n in range(-21, 30, 3): print('{:3d}  =>  {:3d}'.format(n, round_to_nearest(n, 5)))
-21  =>  -20
-18  =>  -20
-15  =>  -15
-12  =>  -10
 -9  =>  -10
 -6  =>   -5
 -3  =>   -5
  0  =>    0
  3  =>    5
  6  =>    5
  9  =>   10
 12  =>   10
 15  =>   15
 18  =>   20
 21  =>   20
 24  =>   25
 27  =>   25

Use:

>>> def round_to_nearest(n, m):
        r = n % m
        return n + m - r if r + r >= m else n - r

It does not use multiplication and will not convert from/to floats.

Rounding to the nearest multiple of 10:

>>> for n in range(-21, 30, 3): print('{:3d}  =>  {:3d}'.format(n, round_to_nearest(n, 10)))
-21  =>  -20
-18  =>  -20
-15  =>  -10
-12  =>  -10
 -9  =>  -10
 -6  =>  -10
 -3  =>    0
  0  =>    0
  3  =>    0
  6  =>   10
  9  =>   10
 12  =>   10
 15  =>   20
 18  =>   20
 21  =>   20
 24  =>   20
 27  =>   30

As you can see, it works for both negative and positive numbers. Ties (e.g. -15 and 15) will always be rounded upwards.

A similar example that rounds to the nearest multiple of 5, demonstrating that it also behaves as expected for a different “base”:

>>> for n in range(-21, 30, 3): print('{:3d}  =>  {:3d}'.format(n, round_to_nearest(n, 5)))
-21  =>  -20
-18  =>  -20
-15  =>  -15
-12  =>  -10
 -9  =>  -10
 -6  =>   -5
 -3  =>   -5
  0  =>    0
  3  =>    5
  6  =>    5
  9  =>   10
 12  =>   10
 15  =>   15
 18  =>   20
 21  =>   20
 24  =>   25
 27  =>   25

回答 9

如果有人需要“财务四舍五入”(总是向上0.5舍入):

def myround(x, base=5):
    roundcontext = decimal.Context(rounding=decimal.ROUND_HALF_UP)
    decimal.setcontext(roundcontext)
    return int(base *float(decimal.Decimal(x/base).quantize(decimal.Decimal('0'))))

根据文档,其他舍入选项是:

ROUND_CEILING(朝着无穷大),
ROUND_DOWN(朝着零大),ROUND_FLOOR(朝着-无限大),
ROUND_HALF_DOWN(朝着
带零的关系最接近),
ROUND_HALF_EVEN(朝着带偶数的最接近偶数),
ROUND_HALF_UP(远离零)或
ROUND_UP(远离零)。
ROUND_05UP(如果四舍五入后的最后一位数字为零,则为零;否则为零)

默认情况下,Python使用ROUND_HALF_EVEN,因为它具有一些统计上的优势(四舍五入的结果没有偏差)。

In case someone needs “financial rounding” (0.5 rounds always up):

def myround(x, base=5):
    roundcontext = decimal.Context(rounding=decimal.ROUND_HALF_UP)
    decimal.setcontext(roundcontext)
    return int(base *float(decimal.Decimal(x/base).quantize(decimal.Decimal('0'))))

As per documentation other rounding options are:

ROUND_CEILING (towards Infinity),
ROUND_DOWN (towards zero),
ROUND_FLOOR (towards -Infinity),
ROUND_HALF_DOWN (to nearest with ties going towards zero),
ROUND_HALF_EVEN (to nearest with ties going to nearest even integer),
ROUND_HALF_UP (to nearest with ties going away from zero), or
ROUND_UP (away from zero).
ROUND_05UP (away from zero if last digit after rounding towards zero would have been 0 or 5; otherwise towards zero)

By default Python uses ROUND_HALF_EVEN as it has some statistical advantages (the rounded results are not biased).


回答 10

对于整数和Python 3:

def divround_down(value, step):
    return value//step*step


def divround_up(value, step):
    return (value+step-1)//step*step

生产:

>>> [divround_down(x,5) for x in range(20)]
[0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 10, 10, 10, 10, 10, 15, 15, 15, 15, 15]
>>> [divround_up(x,5) for x in range(20)]
[0, 5, 5, 5, 5, 5, 10, 10, 10, 10, 10, 15, 15, 15, 15, 15, 20, 20, 20, 20]

For integers and with Python 3:

def divround_down(value, step):
    return value//step*step


def divround_up(value, step):
    return (value+step-1)//step*step

Producing:

>>> [divround_down(x,5) for x in range(20)]
[0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 10, 10, 10, 10, 10, 15, 15, 15, 15, 15]
>>> [divround_up(x,5) for x in range(20)]
[0, 5, 5, 5, 5, 5, 10, 10, 10, 10, 10, 15, 15, 15, 15, 15, 20, 20, 20, 20]

回答 11

那这个呢:

 def divround(value, step):
     return divmod(value, step)[0] * step

What about this:

 def divround(value, step):
     return divmod(value, step)[0] * step

回答 12

下一个5的倍数

考虑到51需要转换为55:

code here

mark = 51;
r = 100 - mark;
a = r%5;
new_mark = mark + a;

Next multiple of 5

Consider 51 needs to be converted to 55:

code here

mark = 51;
r = 100 - mark;
a = r%5;
new_mark = mark + a;

回答 13

这是我的C代码。如果我理解正确,应该应该是这样。

#include <stdio.h>

int main(){
int number;

printf("Enter number: \n");
scanf("%d" , &number);

if(number%5 == 0)
    printf("It is multiple of 5\n");
else{
    while(number%5 != 0)
        number++;
  printf("%d\n",number);
  }
}

并且四舍五入到最接近的5的倍数,而不仅仅是四舍五入;

#include <stdio.h>

int main(){
int number;

printf("Enter number: \n");
scanf("%d" , &number);

if(number%5 == 0)
    printf("It is multiple of 5\n");
else{
    while(number%5 != 0)
        if (number%5 < 3)
            number--;
        else
        number++;
  printf("nearest multiple of 5 is: %d\n",number);
  }
}

Here is my C code. If I understand it correctly, it should supposed to be something like this;

#include <stdio.h>

int main(){
int number;

printf("Enter number: \n");
scanf("%d" , &number);

if(number%5 == 0)
    printf("It is multiple of 5\n");
else{
    while(number%5 != 0)
        number++;
  printf("%d\n",number);
  }
}

and this also rounds to nearest multiple of 5 instead of just rounding up;

#include <stdio.h>

int main(){
int number;

printf("Enter number: \n");
scanf("%d" , &number);

if(number%5 == 0)
    printf("It is multiple of 5\n");
else{
    while(number%5 != 0)
        if (number%5 < 3)
            number--;
        else
        number++;
  printf("nearest multiple of 5 is: %d\n",number);
  }
}

回答 14

另一种方法(没有显式乘法或除法运算符):

def rnd(x, b=5):
    return round(x + min(-(x % b), b - (x % b), key=abs))

Another way to do this (without explicit multiplication or division operators):

def rnd(x, b=5):
    return round(x + min(-(x % b), b - (x % b), key=abs))

回答 15

您可以int()通过添加0.5到传递的数字来“欺骗” 四舍五入,而不是四舍五入int()

You can “trick” int() into rounding off instead of rounding down by adding 0.5 to the number you pass to int().


为什么4 * 0.1的浮点值在Python 3中看起来不错,但3 * 0.1却不这样?

问题:为什么4 * 0.1的浮点值在Python 3中看起来不错,但3 * 0.1却不这样?

我知道大多数小数都没有确切的浮点表示形式(浮点数学运算符是否损坏?)。

但是,当两个值实际上都具有丑陋的十进制表示形式时,我看不出为什么4*0.1将其很好地打印为0.4,但3*0.1不是这样:

>>> 3*0.1
0.30000000000000004
>>> 4*0.1
0.4
>>> from decimal import Decimal
>>> Decimal(3*0.1)
Decimal('0.3000000000000000444089209850062616169452667236328125')
>>> Decimal(4*0.1)
Decimal('0.40000000000000002220446049250313080847263336181640625')

I know that most decimals don’t have an exact floating point representation (Is floating point math broken?).

But I don’t see why 4*0.1 is printed nicely as 0.4, but 3*0.1 isn’t, when both values actually have ugly decimal representations:

>>> 3*0.1
0.30000000000000004
>>> 4*0.1
0.4
>>> from decimal import Decimal
>>> Decimal(3*0.1)
Decimal('0.3000000000000000444089209850062616169452667236328125')
>>> Decimal(4*0.1)
Decimal('0.40000000000000002220446049250313080847263336181640625')

回答 0

简单的答案是因为3*0.1 != 0.3归因于量化(四舍五入)误差(而4*0.1 == 0.4乘以2的幂通常是“精确”运算)。

您可以.hex在Python中使用该方法查看数字的内部表示形式(基本上是确切的二进制浮点值,而不是以10为底的近似值)。这可以帮助解释幕后情况。

>>> (0.1).hex()
'0x1.999999999999ap-4'
>>> (0.3).hex()
'0x1.3333333333333p-2'
>>> (0.1*3).hex()
'0x1.3333333333334p-2'
>>> (0.4).hex()
'0x1.999999999999ap-2'
>>> (0.1*4).hex()
'0x1.999999999999ap-2'

0.1是0x1.999999999999a乘以2 ^ -4。末尾的“ a”表示数字10-换句话说,二进制浮点数中的0.1 略大于 “精确”值0.1(因为最终的0x0.99舍入为0x0.a)。当您将其乘以4(2的幂)时,指数会上移(从2 ^ -4到2 ^ -2),但数字不变,所以4*0.1 == 0.4

但是,当乘以3时,0x0.99与0x0.a0(0x0.07)之间的微小差异会放大为0x0.15错误,在最后一个位置显示为一位错误。这将导致0.1 * 3 略大于 0.3的舍入值。

Python 3的float repr被设计为可双向访问的,也就是说,显示的值应完全可转换为原始值。因此,它无法显示0.30.1*3完全相同的方式,或两个不同的数字最终会往返后相同。因此,Python 3的repr引擎选择显示一个略有明显错误的引擎。

The simple answer is because 3*0.1 != 0.3 due to quantization (roundoff) error (whereas 4*0.1 == 0.4 because multiplying by a power of two is usually an “exact” operation). Python tries to find the shortest string that would round to the desired value, so it can display 4*0.1 as 0.4 as these are equal, but it cannot display 3*0.1 as 0.3 because these are not equal.

You can use the .hex method in Python to view the internal representation of a number (basically, the exact binary floating point value, rather than the base-10 approximation). This can help to explain what’s going on under the hood.

>>> (0.1).hex()
'0x1.999999999999ap-4'
>>> (0.3).hex()
'0x1.3333333333333p-2'
>>> (0.1*3).hex()
'0x1.3333333333334p-2'
>>> (0.4).hex()
'0x1.999999999999ap-2'
>>> (0.1*4).hex()
'0x1.999999999999ap-2'

0.1 is 0x1.999999999999a times 2^-4. The “a” at the end means the digit 10 – in other words, 0.1 in binary floating point is very slightly larger than the “exact” value of 0.1 (because the final 0x0.99 is rounded up to 0x0.a). When you multiply this by 4, a power of two, the exponent shifts up (from 2^-4 to 2^-2) but the number is otherwise unchanged, so 4*0.1 == 0.4.

However, when you multiply by 3, the tiny little difference between 0x0.99 and 0x0.a0 (0x0.07) magnifies into a 0x0.15 error, which shows up as a one-digit error in the last position. This causes 0.1*3 to be very slightly larger than the rounded value of 0.3.

Python 3’s float repr is designed to be round-trippable, that is, the value shown should be exactly convertible into the original value (float(repr(f)) == f for all floats f). Therefore, it cannot display 0.3 and 0.1*3 exactly the same way, or the two different numbers would end up the same after round-tripping. Consequently, Python 3’s repr engine chooses to display one with a slight apparent error.


回答 1

reprstr在Python 3中)将根据需要输出尽可能多的数字,以使该值明确。在这种情况下,相乘的结果3*0.1不是最接近0.3的值(十六进制为0x1.3333333333333p-2),实际上是高了一个LSB​​(0x1.3333333333334p-2),因此它需要更多的数字才能与0.3区分。

另一方面,乘法4*0.1 的确获得了最接近0.4的值(十六进制为0x1.999999999999ap-2),因此不需要任何其他数字。

您可以很容易地验证这一点:

>>> 3*0.1 == 0.3
False
>>> 4*0.1 == 0.4
True

我在上面使用了十六进制表示法,因为它既美观又紧凑,并且显示了两个值之间的位差。您可以使用eg自己执行此操作(3*0.1).hex()。如果您希望以全部十进制的形式查看它们,请执行以下操作:

>>> Decimal(3*0.1)
Decimal('0.3000000000000000444089209850062616169452667236328125')
>>> Decimal(0.3)
Decimal('0.299999999999999988897769753748434595763683319091796875')
>>> Decimal(4*0.1)
Decimal('0.40000000000000002220446049250313080847263336181640625')
>>> Decimal(0.4)
Decimal('0.40000000000000002220446049250313080847263336181640625')

repr (and str in Python 3) will put out as many digits as required to make the value unambiguous. In this case the result of the multiplication 3*0.1 isn’t the closest value to 0.3 (0x1.3333333333333p-2 in hex), it’s actually one LSB higher (0x1.3333333333334p-2) so it needs more digits to distinguish it from 0.3.

On the other hand, the multiplication 4*0.1 does get the closest value to 0.4 (0x1.999999999999ap-2 in hex), so it doesn’t need any additional digits.

You can verify this quite easily:

>>> 3*0.1 == 0.3
False
>>> 4*0.1 == 0.4
True

I used hex notation above because it’s nice and compact and shows the bit difference between the two values. You can do this yourself using e.g. (3*0.1).hex(). If you’d rather see them in all their decimal glory, here you go:

>>> Decimal(3*0.1)
Decimal('0.3000000000000000444089209850062616169452667236328125')
>>> Decimal(0.3)
Decimal('0.299999999999999988897769753748434595763683319091796875')
>>> Decimal(4*0.1)
Decimal('0.40000000000000002220446049250313080847263336181640625')
>>> Decimal(0.4)
Decimal('0.40000000000000002220446049250313080847263336181640625')

回答 2

这是其他答案的简化结论。

如果您在Python的命令行上检查浮点数或将其打印,它将通过repr创建其字符串表示形式的函数。

从3.2版开始,Python strrepr使用复杂的舍入机制,其更喜欢好看的小数,如果有可能,但使用更多的数字在需要保证双射(一个一对一)映射花车和它们的字符串表示之间。

这种方案保证repr(float(s))即使简单的小数点不能精确地表示为浮点数(例如when),其值对于简单的小数点也看起来不错s = "0.1")

同时,它保证float(repr(x)) == x每个浮动都成立x

Here’s a simplified conclusion from other answers.

If you check a float on Python’s command line or print it, it goes through function repr which creates its string representation.

Starting with version 3.2, Python’s str and repr use a complex rounding scheme, which prefers nice-looking decimals if possible, but uses more digits where necessary to guarantee bijective (one-to-one) mapping between floats and their string representations.

This scheme guarantees that value of repr(float(s)) looks nice for simple decimals, even if they can’t be represented precisely as floats (eg. when s = "0.1").

At the same time it guarantees that float(repr(x)) == x holds for every float x


回答 3

并不是真的特定于Python的实现,而是应该适用于任何浮点数到十进制字符串的函数。

浮点数本质上是一个二进制数,但以科学计数法表示,有效数字的固定限制。

具有不与底数共享的质数因子的任何数字的逆将始终导致重复的点表示。例如1/7的素数为7,与10不共享,因此具有重复的十进制表示形式,素数为2和5的1/10也是如此,后者不与2共享; 这意味着0.1不能由点后的有限位数精确表示。

由于0.1没有精确的表示形式,因此将近似值转换为小数点字符串的函数通常将尝试近似某些值,以使它们不会像0.1000000000004121那样获得不直观的结果。

由于浮点数是科学计数法,因此任何乘以基数的幂只会影响数的指数部分。例如,十进制表示法为1.231e + 2 * 100 = 1.231e + 4,同样,二进制表示法为1.00101010e11 * 100 = 1.00101010e101。如果我乘以非底数的幂,则有效数字也会受到影响。例如1.2e1 * 3 = 3.6e1

根据所使用的算法,它可能会尝试仅根据有效数字来猜测常见的小数。0.1和0.4都具有相同的二进制有效数字,因为它们的浮点数本质上分别是(8/5)(2 ^ -4)和(8/5)(2 ^ -6)的截断。如果该算法将8/5 sigfig模式标识为十进制1.6,则它将适用于0.1、0.2、0.4、0.8等。对于其他组合(例如,浮点数3除以浮点数10),它也可能具有魔术的sigfig模式。以及其他统计上可能由10除以形成的魔术图案。

在3 * 0.1的情况下,最后几个有效数字可能与将浮点数3除以浮点数10有所不同,从而导致算法无法根据其对精度损失的容忍度来识别0.3常数的幻数。

编辑:https//docs.python.org/3.1/tutorial/floatingpoint.html

有趣的是,有许多不同的十进制数字共享相同的最接近的近似二进制分数。例如,数字0.1和0.10000000000000001和0.1000000000000000055511151231257827021181583404541015625都由3602879701896397/2 ** 55近似。由于所有这些十进制值都具有相同的近似值,因此可以显示其中任何一个,同时仍保留不变的eval(repr(x) )== x。

对于精度损失没有容忍度,如果float x(0.3)不完全等于float y(0.1 * 3),则repr(x)不完全等于repr(y)。

Not really specific to Python’s implementation but should apply to any float to decimal string functions.

A floating point number is essentially a binary number, but in scientific notation with a fixed limit of significant figures.

The inverse of any number that has a prime number factor that is not shared with the base will always result in a recurring dot point representation. For example 1/7 has a prime factor, 7, that is not shared with 10, and therefore has a recurring decimal representation, and the same is true for 1/10 with prime factors 2 and 5, the latter not being shared with 2; this means that 0.1 cannot be exactly represented by a finite number of bits after the dot point.

Since 0.1 has no exact representation, a function that converts the approximation to a decimal point string will usually try to approximate certain values so that they don’t get unintuitive results like 0.1000000000004121.

Since the floating point is in scientific notation, any multiplication by a power of the base only affects the exponent part of the number. For example 1.231e+2 * 100 = 1.231e+4 for decimal notation, and likewise, 1.00101010e11 * 100 = 1.00101010e101 in binary notation. If I multiply by a non-power of the base, the significant digits will also be affected. For example 1.2e1 * 3 = 3.6e1

Depending on the algorithm used, it may try to guess common decimals based on the significant figures only. Both 0.1 and 0.4 have the same significant figures in binary, because their floats are essentially truncations of (8/5)(2^-4) and (8/5)(2^-6) respectively. If the algorithm identifies the 8/5 sigfig pattern as the decimal 1.6, then it will work on 0.1, 0.2, 0.4, 0.8, etc. It may also have magic sigfig patterns for other combinations, such as the float 3 divided by float 10 and other magic patterns statistically likely to be formed by division by 10.

In the case of 3*0.1, the last few significant figures will likely be different from dividing a float 3 by float 10, causing the algorithm to fail to recognize the magic number for the 0.3 constant depending on its tolerance for precision loss.

Edit: https://docs.python.org/3.1/tutorial/floatingpoint.html

Interestingly, there are many different decimal numbers that share the same nearest approximate binary fraction. For example, the numbers 0.1 and 0.10000000000000001 and 0.1000000000000000055511151231257827021181583404541015625 are all approximated by 3602879701896397 / 2 ** 55. Since all of these decimal values share the same approximation, any one of them could be displayed while still preserving the invariant eval(repr(x)) == x.

There is no tolerance for precision loss, if float x (0.3) is not exactly equal to float y (0.1*3), then repr(x) is not exactly equal to repr(y).


如何在Python中将数字四舍五入为有效数字

问题:如何在Python中将数字四舍五入为有效数字

我需要四舍五入才能在UI中显示。例如,一个重要的数字:

1234-> 1000

0.12-> 0.1

0.012-> 0.01

0.062-> 0.06

6253-> 6000

1999-> 2000

是否有使用Python库执行此操作的好方法,还是我必须自己编写它?

I need to round a float to be displayed in a UI. E.g, to one significant figure:

1234 -> 1000

0.12 -> 0.1

0.012 -> 0.01

0.062 -> 0.06

6253 -> 6000

1999 -> 2000

Is there a nice way to do this using the Python library, or do I have to write it myself?


回答 0

您可以使用负数舍入整数:

>>> round(1234, -3)
1000.0

因此,如果您只需要最高有效数字:

>>> from math import log10, floor
>>> def round_to_1(x):
...   return round(x, -int(floor(log10(abs(x)))))
... 
>>> round_to_1(0.0232)
0.02
>>> round_to_1(1234243)
1000000.0
>>> round_to_1(13)
10.0
>>> round_to_1(4)
4.0
>>> round_to_1(19)
20.0

如果大于1,则可能需要将float转换为整数。

You can use negative numbers to round integers:

>>> round(1234, -3)
1000.0

Thus if you need only most significant digit:

>>> from math import log10, floor
>>> def round_to_1(x):
...   return round(x, -int(floor(log10(abs(x)))))
... 
>>> round_to_1(0.0232)
0.02
>>> round_to_1(1234243)
1000000.0
>>> round_to_1(13)
10.0
>>> round_to_1(4)
4.0
>>> round_to_1(19)
20.0

You’ll probably have to take care of turning float to integer if it’s bigger than 1.


回答 1

字符串格式的%g将格式化浮点数,并四舍五入到有效数字。有时会使用科学的“ e”表示法,因此将舍入的字符串转换回浮点数,然后通过%s字符串格式进行格式化。

>>> '%s' % float('%.1g' % 1234)
'1000'
>>> '%s' % float('%.1g' % 0.12)
'0.1'
>>> '%s' % float('%.1g' % 0.012)
'0.01'
>>> '%s' % float('%.1g' % 0.062)
'0.06'
>>> '%s' % float('%.1g' % 6253)
'6000.0'
>>> '%s' % float('%.1g' % 1999)
'2000.0'

%g in string formatting will format a float rounded to some number of significant figures. It will sometimes use ‘e’ scientific notation, so convert the rounded string back to a float then through %s string formatting.

>>> '%s' % float('%.1g' % 1234)
'1000'
>>> '%s' % float('%.1g' % 0.12)
'0.1'
>>> '%s' % float('%.1g' % 0.012)
'0.01'
>>> '%s' % float('%.1g' % 0.062)
'0.06'
>>> '%s' % float('%.1g' % 6253)
'6000.0'
>>> '%s' % float('%.1g' % 1999)
'2000.0'

回答 2

如果要使用除1个有效小数之外的其他数字(否则与Evgeny相同):

>>> from math import log10, floor
>>> def round_sig(x, sig=2):
...   return round(x, sig-int(floor(log10(abs(x))))-1)
... 
>>> round_sig(0.0232)
0.023
>>> round_sig(0.0232, 1)
0.02
>>> round_sig(1234243, 3)
1230000.0

If you want to have other than 1 significant decimal (otherwise the same as Evgeny):

>>> from math import log10, floor
>>> def round_sig(x, sig=2):
...   return round(x, sig-int(floor(log10(abs(x))))-1)
... 
>>> round_sig(0.0232)
0.023
>>> round_sig(0.0232, 1)
0.02
>>> round_sig(1234243, 3)
1230000.0

回答 3

f'{float(f"{i:.1g}"):g}'
# Or with Python <3.6,
'{:g}'.format(float('{:.1g}'.format(i)))

该解决方案与所有其他解决方案不同,因为:

  1. 恰好解决了OP问题
  2. 它并没有需要任何额外的包
  3. 需要任何用户定义的辅助功能数学运算

对于任意数量n的有效数字,可以使用:

print('{:g}'.format(float('{:.{p}g}'.format(i, p=n))))

测试:

a = [1234, 0.12, 0.012, 0.062, 6253, 1999, -3.14, 0., -48.01, 0.75]
b = ['{:g}'.format(float('{:.1g}'.format(i))) for i in a]
# b == ['1000', '0.1', '0.01', '0.06', '6000', '2000', '-3', '0', '-50', '0.8']

注意:使用此解决方案,不可能从输入动态地调整有效数字的数量,因为没有标准的方法来区分具有不同尾随零的数字(3.14 == 3.1400)。如果需要这样做,则需要非标准功能,例如精确度软件包中提供的功能。

f'{float(f"{i:.1g}"):g}'
# Or with Python <3.6,
'{:g}'.format(float('{:.1g}'.format(i)))

This solution is different from all of the others because:

  1. it exactly solves the OP question
  2. it does not need any extra package
  3. it does not need any user-defined auxiliary function or mathematical operation

For an arbitrary number n of significant figures, you can use:

print('{:g}'.format(float('{:.{p}g}'.format(i, p=n))))

Test:

a = [1234, 0.12, 0.012, 0.062, 6253, 1999, -3.14, 0., -48.01, 0.75]
b = ['{:g}'.format(float('{:.1g}'.format(i))) for i in a]
# b == ['1000', '0.1', '0.01', '0.06', '6000', '2000', '-3', '0', '-50', '0.8']

Note: with this solution, it is not possible to adapt the number of significant figures dynamically from the input because there is no standard way to distinguish numbers with different numbers of trailing zeros (3.14 == 3.1400). If you need to do so, then non-standard functions like the ones provided in the to-precision package are needed.


回答 4

我已经创建了可以满足您需求的高精度软件包。它使您可以为数字赋予或多或少的有效数字。

它还输出带有指定数量有效数字的标准,科学和工程符号。

在接受的答案中有一行

>>> round_to_1(1234243)
1000000.0

实际上指定了8个无花果。对于数字1234243,我的图书馆仅显示一个有效数字:

>>> from to_precision import to_precision
>>> to_precision(1234243, 1, 'std')
'1000000'
>>> to_precision(1234243, 1, 'sci')
'1e6'
>>> to_precision(1234243, 1, 'eng')
'1e6'

还将舍入最后一个有效数字,如果未指定符号,则可以自动选择要使用的符号:

>>> to_precision(599, 2)
'600'
>>> to_precision(1164, 2)
'1.2e3'

I have created the package to-precision that does what you want. It allows you to give your numbers more or less significant figures.

It also outputs standard, scientific, and engineering notation with a specified number of significant figures.

In the accepted answer there is the line

>>> round_to_1(1234243)
1000000.0

That actually specifies 8 sig figs. For the number 1234243 my library only displays one significant figure:

>>> from to_precision import to_precision
>>> to_precision(1234243, 1, 'std')
'1000000'
>>> to_precision(1234243, 1, 'sci')
'1e6'
>>> to_precision(1234243, 1, 'eng')
'1e6'

It will also round the last significant figure and can automatically choose what notation to use if a notation isn’t specified:

>>> to_precision(599, 2)
'600'
>>> to_precision(1164, 2)
'1.2e3'

回答 5

将整数四舍五入到1位有效数字的基本思想是将其转换为浮点数,该浮点数在该点之前1位数并四舍五入,然后将其转换回其原始整数大小。

为此,我们需要知道小于整数10的最大幂。为此,我们可以使用log 10功能的下限。

from math import log10, floor
def round_int(i,places):
    if i == 0:
        return 0
    isign = i/abs(i)
    i = abs(i)
    if i < 1:
        return 0
    max10exp = floor(log10(i))
    if max10exp+1 < places:
        return i
    sig10pow = 10**(max10exp-places+1)
    floated = i*1.0/sig10pow
    defloated = round(floated)*sig10pow
    return int(defloated*isign)

To round an integer to 1 significant figure the basic idea is to convert it to a floating point with 1 digit before the point and round that, then convert it back to its original integer size.

To do this we need to know the largest power of 10 less than the integer. We can use floor of the log 10 function for this.

from math import log10, floor
def round_int(i,places):
    if i == 0:
        return 0
    isign = i/abs(i)
    i = abs(i)
    if i < 1:
        return 0
    max10exp = floor(log10(i))
    if max10exp+1 < places:
        return i
    sig10pow = 10**(max10exp-places+1)
    floated = i*1.0/sig10pow
    defloated = round(floated)*sig10pow
    return int(defloated*isign)

回答 6

为了直接回答这个问题,这是我使用R函数命名的版本:

import math

def signif(x, digits=6):
    if x == 0 or not math.isfinite(x):
        return x
    digits -= math.ceil(math.log10(abs(x)))
    return round(x, digits)

我发布此答案的主要原因是评论抱怨“ 0.075”舍入为0.07而不是0.08。如“新手C”所指出的,这是由于具有有限精度和以2为底的表示形式的浮点运算的组合。实际上可以表示的最接近0.075的数字要小一些,因此舍入的结果与您可能天真地期望的不同。

还要注意,这适用于任何非十进制浮点算法的使用,例如C和Java都有相同的问题。

为了更详细地显示,我们要求Python将数字格式化为“十六进制”格式:

0.075.hex()

这给了我们:0x1.3333333333333p-4。这样做的原因是正常的十进制表示形式通常涉及舍入,因此不是计算机实际“看到”数字的方式。如果您不习惯这种格式,那么Python docsC standard是两个有用的参考。

为了说明这些数字是如何工作的,我们可以通过以下操作回到起点:

0x13333333333333 / 16**13 * 2**-4

应该打印出来0.07516**13是因为小数点后有13个十六进制数字,并且2**-4是因为十六进制指数是以2为底的。

现在我们有了关于浮点数表示方式的一些想法,可以使用decimal模块为我们提供更多的精度,向我们展示发生了什么事情:

from decimal import Decimal

Decimal(0x13333333333333) / 16**13 / 2**4

给:0.07499999999999999722444243844并希望解释为什么round(0.075, 2)评估0.07

To directly answer the question, here’s my version using naming from the R function:

import math

def signif(x, digits=6):
    if x == 0 or not math.isfinite(x):
        return x
    digits -= math.ceil(math.log10(abs(x)))
    return round(x, digits)

My main reason for posting this answer are the comments complaining that “0.075” rounds to 0.07 rather than 0.08. This is due, as pointed out by “Novice C”, to a combination of floating point arithmetic having both finite precision and a base-2 representation. The nearest number to 0.075 that can actually be represented is slightly smaller, hence rounding comes out differently than you might naively expect.

Also note that this applies to any use of non-decimal floating point arithmetic, e.g. C and Java both have the same issue.

To show in more detail, we ask Python to format the number in “hex” format:

0.075.hex()

which gives us: 0x1.3333333333333p-4. The reason for doing this is that the normal decimal representation often involves rounding and hence is not how the computer actually “sees” the number. If you’re not used to this format, a couple of useful references are the Python docs and the C standard.

To show how these numbers work a bit, we can get back to our starting point by doing:

0x13333333333333 / 16**13 * 2**-4

which should should print out 0.075. 16**13 is because there are 13 hexadecimal digits after the decimal point, and 2**-4 is because hex exponents are base-2.

Now we have some idea of how floats are represented we can use the decimal module to give us some more precision, showing us what’s going on:

from decimal import Decimal

Decimal(0x13333333333333) / 16**13 / 2**4

giving: 0.07499999999999999722444243844 and hopefully explaining why round(0.075, 2) evaluates to 0.07


回答 7

def round_to_n(x, n):
    if not x: return 0
    power = -int(math.floor(math.log10(abs(x)))) + (n - 1)
    factor = (10 ** power)
    return round(x * factor) / factor

round_to_n(0.075, 1)      # 0.08
round_to_n(0, 1)          # 0
round_to_n(-1e15 - 1, 16) # 1000000000000001.0

希望能充分利用以上所有答案中的最佳答案(减去能够将其表示为一行lambda的意思;)。尚未探索,请随时编辑此答案:

round_to_n(1e15 + 1, 11)  # 999999999999999.9
def round_to_n(x, n):
    if not x: return 0
    power = -int(math.floor(math.log10(abs(x)))) + (n - 1)
    factor = (10 ** power)
    return round(x * factor) / factor

round_to_n(0.075, 1)      # 0.08
round_to_n(0, 1)          # 0
round_to_n(-1e15 - 1, 16) # 1000000000000001.0

Hopefully taking the best of all the answers above (minus being able to put it as a one line lambda 😉 ). Haven’t explored yet, feel free to edit this answer:

round_to_n(1e15 + 1, 11)  # 999999999999999.9

回答 8

我修改了indgar的解决方案,以处理负数和小数(包括零)。

from math import log10, floor
def round_sig(x, sig=6, small_value=1.0e-9):
    return round(x, sig - int(floor(log10(max(abs(x), abs(small_value))))) - 1)

I modified indgar’s solution to handle negative numbers and small numbers (including zero).

from math import log10, floor
def round_sig(x, sig=6, small_value=1.0e-9):
    return round(x, sig - int(floor(log10(max(abs(x), abs(small_value))))) - 1)

回答 9

如果您想不涉及字符串而四舍五入,我发现上面的链接中隐藏了该链接:

http://code.activestate.com/lists/python-tutor/70739/

给我最好的印象 然后,当您使用任何字符串格式的描述符进行打印时,您将获得一个合理的输出,并且可以将数字表示形式用于其他计算目的。

链接上的代码由三部分组成:def,doc和return。它有一个错误:您需要检查对数是否爆炸。那很容易。将输入与进行比较sys.float_info.min。完整的解决方案是:

import sys,math

def tidy(x, n):
"""Return 'x' rounded to 'n' significant digits."""
y=abs(x)
if y <= sys.float_info.min: return 0.0
return round( x, int( n-math.ceil(math.log10(y)) ) )

它适用于任何标量数值,float如果由于某种原因需要移动响应,n可以为a 。您实际上可以将限制提高到:

sys.float_info.min*sys.float_info.epsilon

如果您出于某些原因正在使用极小的值,则不会引发错误。

If you want to round without involving strings, the link I found buried in the comments above:

http://code.activestate.com/lists/python-tutor/70739/

strikes me as best. Then when you print with any string formatting descriptors, you get a reasonable output, and you can use the numeric representation for other calculation purposes.

The code at the link is a three liner: def, doc, and return. It has a bug: you need to check for exploding logarithms. That is easy. Compare the input to sys.float_info.min. The complete solution is:

import sys,math

def tidy(x, n):
"""Return 'x' rounded to 'n' significant digits."""
y=abs(x)
if y <= sys.float_info.min: return 0.0
return round( x, int( n-math.ceil(math.log10(y)) ) )

It works for any scalar numeric value, and n can be a float if you need to shift the response for some reason. You can actually push the limit to:

sys.float_info.min*sys.float_info.epsilon

without provoking an error, if for some reason you are working with miniscule values.


回答 10

我想不出任何能够立即解决的问题。但是对于浮点数来说,它处理得很好。

>>> round(1.2322, 2)
1.23

整数比较棘手。它们不会以10为基数存储在内存中,因此重要的地方并不是自然而然的事情。但是,一旦成为字符串,实现起来就很简单了。

或对于整数:

>>> def intround(n, sigfigs):
...   n = str(n)
...   return n[:sigfigs] + ('0' * (len(n)-(sigfigs)))

>>> intround(1234, 1)
'1000'
>>> intround(1234, 2)

如果您想创建一个可以处理任何数字的函数,我的偏好是将它们都转换为字符串,并寻找一个小数位来决定要做什么:

>>> def roundall1(n, sigfigs):
...   n = str(n)
...   try:
...     sigfigs = n.index('.')
...   except ValueError:
...     pass
...   return intround(n, sigfigs)

另一种选择是检查类型。这将不太灵活,并且可能无法与其他数字(例如Decimal对象)很好地配合使用:

>>> def roundall2(n, sigfigs):
...   if type(n) is int: return intround(n, sigfigs)
...   else: return round(n, sigfigs)

I can’t think of anything that would be able to handle this out of the box. But it’s fairly well handled for floating point numbers.

>>> round(1.2322, 2)
1.23

Integers are trickier. They’re not stored as base 10 in memory, so significant places isn’t a natural thing to do. It’s fairly trivial to implement once they’re a string though.

Or for integers:

>>> def intround(n, sigfigs):
...   n = str(n)
...   return n[:sigfigs] + ('0' * (len(n)-(sigfigs)))

>>> intround(1234, 1)
'1000'
>>> intround(1234, 2)

If you would like to create a function that handles any number, my preference would be to convert them both to strings and look for a decimal place to decide what to do:

>>> def roundall1(n, sigfigs):
...   n = str(n)
...   try:
...     sigfigs = n.index('.')
...   except ValueError:
...     pass
...   return intround(n, sigfigs)

Another option is to check for type. This will be far less flexible, and will probably not play nicely with other numbers such as Decimal objects:

>>> def roundall2(n, sigfigs):
...   if type(n) is int: return intround(n, sigfigs)
...   else: return round(n, sigfigs)

回答 11

给出的答案是给出的最好的答案,但是它有很多限制,并且在技术上没有正确的有效数字。

numpy.format_float_positional直接支持所需的行为。以下片段将浮点数x格式化为4个有效数字,并取消了科学计数法。

import numpy as np
x=12345.6
np.format_float_positional(x, precision=4, unique=False, fractional=False, trim='k')
> 12340.

The posted answer was the best available when given, but it has a number of limitations and does not produce technically correct significant figures.

numpy.format_float_positional supports the desired behaviour directly. The following fragment returns the float x formatted to 4 significant figures, with scientific notation suppressed.

import numpy as np
x=12345.6
np.format_float_positional(x, precision=4, unique=False, fractional=False, trim='k')
> 12340.

回答 12

我也遇到了这个问题,但是我需要控制舍入类型。因此,我编写了一个快速函数(请参见下面的代码),该函数可以将值,舍入类型和所需的有效数字考虑在内。

import decimal
from math import log10, floor

def myrounding(value , roundstyle='ROUND_HALF_UP',sig = 3):
    roundstyles = [ 'ROUND_05UP','ROUND_DOWN','ROUND_HALF_DOWN','ROUND_HALF_UP','ROUND_CEILING','ROUND_FLOOR','ROUND_HALF_EVEN','ROUND_UP']

    power =  -1 * floor(log10(abs(value)))
    value = '{0:f}'.format(value) #format value to string to prevent float conversion issues
    divided = Decimal(value) * (Decimal('10.0')**power) 
    roundto = Decimal('10.0')**(-sig+1)
    if roundstyle not in roundstyles:
        print('roundstyle must be in list:', roundstyles) ## Could thrown an exception here if you want.
    return_val = decimal.Decimal(divided).quantize(roundto,rounding=roundstyle)*(decimal.Decimal(10.0)**-power)
    nozero = ('{0:f}'.format(return_val)).rstrip('0').rstrip('.') # strips out trailing 0 and .
    return decimal.Decimal(nozero)


for x in list(map(float, '-1.234 1.2345 0.03 -90.25 90.34543 9123.3 111'.split())):
    print (x, 'rounded UP: ',myrounding(x,'ROUND_UP',3))
    print (x, 'rounded normal: ',myrounding(x,sig=3))

I ran into this as well but I needed control over the rounding type. Thus, I wrote a quick function (see code below) that can take value, rounding type, and desired significant digits into account.

import decimal
from math import log10, floor

def myrounding(value , roundstyle='ROUND_HALF_UP',sig = 3):
    roundstyles = [ 'ROUND_05UP','ROUND_DOWN','ROUND_HALF_DOWN','ROUND_HALF_UP','ROUND_CEILING','ROUND_FLOOR','ROUND_HALF_EVEN','ROUND_UP']

    power =  -1 * floor(log10(abs(value)))
    value = '{0:f}'.format(value) #format value to string to prevent float conversion issues
    divided = Decimal(value) * (Decimal('10.0')**power) 
    roundto = Decimal('10.0')**(-sig+1)
    if roundstyle not in roundstyles:
        print('roundstyle must be in list:', roundstyles) ## Could thrown an exception here if you want.
    return_val = decimal.Decimal(divided).quantize(roundto,rounding=roundstyle)*(decimal.Decimal(10.0)**-power)
    nozero = ('{0:f}'.format(return_val)).rstrip('0').rstrip('.') # strips out trailing 0 and .
    return decimal.Decimal(nozero)


for x in list(map(float, '-1.234 1.2345 0.03 -90.25 90.34543 9123.3 111'.split())):
    print (x, 'rounded UP: ',myrounding(x,'ROUND_UP',3))
    print (x, 'rounded normal: ',myrounding(x,sig=3))

回答 13

使用python 2.6+ 新样式格式(不建议使用%-style):

>>> "{0}".format(float("{0:.1g}".format(1216)))
'1000.0'
>>> "{0}".format(float("{0:.1g}".format(0.00356)))
'0.004'

在python 2.7+中,您可以省略前导0s。

Using python 2.6+ new-style formatting (as %-style is deprecated):

>>> "{0}".format(float("{0:.1g}".format(1216)))
'1000.0'
>>> "{0}".format(float("{0:.1g}".format(0.00356)))
'0.004'

In python 2.7+ you can omit the leading 0s.


回答 14

如果数字大于10 **(-decimal_positions),则此函数进行正常的回合,否则增加更多的小数,直到达到有意义的小数位数为止:

def smart_round(x, decimal_positions):
    dp = - int(math.log10(abs(x))) if x != 0.0 else int(0)
    return round(float(x), decimal_positions + dp if dp > 0 else decimal_positions)

希望能帮助到你。

This function does a normal round if the number is bigger than 10**(-decimal_positions), otherwise adds more decimal until the number of meaningful decimal positions is reached:

def smart_round(x, decimal_positions):
    dp = - int(math.log10(abs(x))) if x != 0.0 else int(0)
    return round(float(x), decimal_positions + dp if dp > 0 else decimal_positions)

Hope it helps.


回答 15

https://stackoverflow.com/users/1391441/gabriel,以下内容是否解决了您对rnd(.075,1)的担忧?警告:以浮点数形式返回值

def round_to_n(x, n):
    fmt = '{:1.' + str(n) + 'e}'    # gives 1.n figures
    p = fmt.format(x).split('e')    # get mantissa and exponent
                                    # round "extra" figure off mantissa
    p[0] = str(round(float(p[0]) * 10**(n-1)) / 10**(n-1))
    return float(p[0] + 'e' + p[1]) # convert str to float

>>> round_to_n(750, 2)
750.0
>>> round_to_n(750, 1)
800.0
>>> round_to_n(.0750, 2)
0.075
>>> round_to_n(.0750, 1)
0.08
>>> math.pi
3.141592653589793
>>> round_to_n(math.pi, 7)
3.141593

https://stackoverflow.com/users/1391441/gabriel, does the following address your concern about rnd(.075, 1)? Caveat: returns value as a float

def round_to_n(x, n):
    fmt = '{:1.' + str(n) + 'e}'    # gives 1.n figures
    p = fmt.format(x).split('e')    # get mantissa and exponent
                                    # round "extra" figure off mantissa
    p[0] = str(round(float(p[0]) * 10**(n-1)) / 10**(n-1))
    return float(p[0] + 'e' + p[1]) # convert str to float

>>> round_to_n(750, 2)
750.0
>>> round_to_n(750, 1)
800.0
>>> round_to_n(.0750, 2)
0.075
>>> round_to_n(.0750, 1)
0.08
>>> math.pi
3.141592653589793
>>> round_to_n(math.pi, 7)
3.141593

回答 16

这将返回一个字符串,以便结果不包含小数部分,并且正确显示了E表示法中否则会出现的较小值:

def sigfig(x, num_sigfig):
    num_decplace = num_sigfig - int(math.floor(math.log10(abs(x)))) - 1
    return '%.*f' % (num_decplace, round(x, num_decplace))

This returns a string, so that results without fractional parts, and small values which would otherwise appear in E notation are shown correctly:

def sigfig(x, num_sigfig):
    num_decplace = num_sigfig - int(math.floor(math.log10(abs(x)))) - 1
    return '%.*f' % (num_decplace, round(x, num_decplace))

回答 17

给定一个如此彻底回答的问题,为什么不添加另一个

尽管上面的许多内容是可比的,但这更适合我的审美观

import numpy as np

number=-456.789
significantFigures=4

roundingFactor=significantFigures - int(np.floor(np.log10(np.abs(number)))) - 1
rounded=np.round(number, roundingFactor)

string=rounded.astype(str)

print(string)

这适用于单个数字和numpy数组,对于负数应该可以正常工作。

我们可能还要增加一个附加步骤-即使四舍五入为整数,np.round()也会返回一个十进制数(即,对于ificantFigures = 2,我们可能期望返回-460,但相反会得到-460.0)。我们可以添加此步骤以更正此问题:

if roundingFactor<=0:
    rounded=rounded.astype(int)

不幸的是,最后一步不适用于数字数组-亲爱的读者,我会把这个留给您看看是否需要。

Given a question so thoroughly answered why not add another

This suits my aesthetic a little better, though many of the above are comparable

import numpy as np

number=-456.789
significantFigures=4

roundingFactor=significantFigures - int(np.floor(np.log10(np.abs(number)))) - 1
rounded=np.round(number, roundingFactor)

string=rounded.astype(str)

print(string)

This works for individual numbers and numpy arrays, and should function fine for negative numbers.

There’s one additional step we might add – np.round() returns a decimal number even if rounded is an integer (i.e. for significantFigures=2 we might expect to get back -460 but instead we get -460.0). We can add this step to correct for that:

if roundingFactor<=0:
    rounded=rounded.astype(int)

Unfortunately, this final step won’t work for an array of numbers – I’ll leave that to you dear reader to figure out if you need.


回答 18

sigfig包/库盖这一点。后安装,你可以做到以下几点:

>>> from sigfig import round
>>> round(1234, 1)
1000
>>> round(0.12, 1)
0.1
>>> round(0.012, 1)
0.01
>>> round(0.062, 1)
0.06
>>> round(6253, 1)
6000
>>> round(1999, 1)
2000

The sigfig package/library covers this. After installing you can do the following:

>>> from sigfig import round
>>> round(1234, 1)
1000
>>> round(0.12, 1)
0.1
>>> round(0.012, 1)
0.01
>>> round(0.062, 1)
0.06
>>> round(6253, 1)
6000
>>> round(1999, 1)
2000

回答 19

import math

  def sig_dig(x, n_sig_dig):
      num_of_digits = len(str(x).replace(".", ""))
      if n_sig_dig >= num_of_digits:
          return x
      n = math.floor(math.log10(x) + 1 - n_sig_dig)
      result = round(10 ** -n * x) * 10 ** n
      return float(str(result)[: n_sig_dig + 1])


    >>> sig_dig(1234243, 3)
    >>> sig_dig(243.3576, 5)

        1230.0
        243.36
import math

  def sig_dig(x, n_sig_dig):
      num_of_digits = len(str(x).replace(".", ""))
      if n_sig_dig >= num_of_digits:
          return x
      n = math.floor(math.log10(x) + 1 - n_sig_dig)
      result = round(10 ** -n * x) * 10 ** n
      return float(str(result)[: n_sig_dig + 1])


    >>> sig_dig(1234243, 3)
    >>> sig_dig(243.3576, 5)

        1230.0
        243.36

如何用Python舍入到两位小数?

问题:如何用Python舍入到两位小数?

在此代码的输出(华氏转摄氏度)中,我得到了很多小数。

我的代码当前如下所示:

def main():
    printC(formeln(typeHere()))

def typeHere():
    global Fahrenheit
    try:
        Fahrenheit = int(raw_input("Hi! Enter Fahrenheit value, and get it in Celsius!\n"))
    except ValueError:
        print "\nYour insertion was not a digit!"
        print "We've put your Fahrenheit value to 50!"
        Fahrenheit = 50
    return Fahrenheit

def formeln(c):
    Celsius = (Fahrenheit - 32.00) * 5.00/9.00
    return Celsius

def printC(answer):
    answer = str(answer)
    print "\nYour Celsius value is " + answer + " C.\n"



main()

所以我的问题是,如何使该程序四舍五入到小数点后第二位?

I am getting a lot of decimals in the output of this code (Fahrenheit to Celsius converter).

My code currently looks like this:

def main():
    printC(formeln(typeHere()))

def typeHere():
    global Fahrenheit
    try:
        Fahrenheit = int(raw_input("Hi! Enter Fahrenheit value, and get it in Celsius!\n"))
    except ValueError:
        print "\nYour insertion was not a digit!"
        print "We've put your Fahrenheit value to 50!"
        Fahrenheit = 50
    return Fahrenheit

def formeln(c):
    Celsius = (Fahrenheit - 32.00) * 5.00/9.00
    return Celsius

def printC(answer):
    answer = str(answer)
    print "\nYour Celsius value is " + answer + " C.\n"



main()

So my question is, how do I make the program round every answer to the 2nd decimal place?


回答 0

您可以使用该round函数,该函数将数字作为第一个参数,第二个参数是小数点后的精度。

在您的情况下,它将是:

answer = str(round(answer, 2))

You can use the round function, which takes as its first argument the number and the second argument is the precision after the decimal point.

In your case, it would be:

answer = str(round(answer, 2))

回答 1

使用str.format()语法,以显示 answer具有两个小数位(不改变的基础值answer):

def printC(answer):
    print("\nYour Celsius value is {:0.2f}ºC.\n".format(answer))

哪里:

  • :介绍格式规范
  • 0 为数字类型启用符号感知零填充
  • .2精度设置为2
  • f 将数字显示为定点数字

Using str.format()‘s syntax to display answer with two decimal places (without altering the underlying value of answer):

def printC(answer):
    print("\nYour Celsius value is {:0.2f}ºC.\n".format(answer))

Where:

  • : introduces the format spec
  • 0 enables sign-aware zero-padding for numeric types
  • .2 sets the precision to 2
  • f displays the number as a fixed-point number

回答 2

大多数答案建议roundformatround有时会四舍五入,就我而言,我需要将变量的四舍五入,而不仅仅是这样显示。

round(2.357, 2)  # -> 2.36

我在这里找到了答案:如何将浮点数四舍五入到小数点后一位?

import math
v = 2.357
print(math.ceil(v*100)/100)  # -> 2.36
print(math.floor(v*100)/100)  # -> 2.35

要么:

from math import floor, ceil

def roundDown(n, d=8):
    d = int('1' + ('0' * d))
    return floor(n * d) / d

def roundUp(n, d=8):
    d = int('1' + ('0' * d))
    return ceil(n * d) / d

Most answers suggested round or format. round sometimes rounds up, and in my case I needed the value of my variable to be rounded down and not just displayed as such.

round(2.357, 2)  # -> 2.36

I found the answer here: How do I round a floating point number up to a certain decimal place?

import math
v = 2.357
print(math.ceil(v*100)/100)  # -> 2.36
print(math.floor(v*100)/100)  # -> 2.35

or:

from math import floor, ceil

def roundDown(n, d=8):
    d = int('1' + ('0' * d))
    return floor(n * d) / d

def roundUp(n, d=8):
    d = int('1' + ('0' * d))
    return ceil(n * d) / d

回答 3

float(str(round(answer, 2)))
float(str(round(0.0556781255, 2)))
float(str(round(answer, 2)))
float(str(round(0.0556781255, 2)))

回答 4

您想四舍五入。

round(value,significantDigit)是执行此操作的常规解决方案,但是,当从数字四舍五入到第一个数字(在其左侧)的下方(在其左侧)具有a时,有时这从数学角度来看并不像预期的那样起作用5

以下是这种不可预测的行为的一些示例:

>>> 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*6),2)

0.08

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

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

基本上,这会在字符串中添加一个很小的值,以强制它在无法预料的情况下正确舍入,而在您无法预期的情况下,通常情况下它不会与round函数配合使用。添加一个方便的值是1e-Xwhere X是您要round在plus上尝试使用的数字字符串的长度1

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

因此,完成的代码将类似于:

def main():
    printC(formeln(typeHere()))

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

def typeHere():
    global Fahrenheit
    try:
        Fahrenheit = int(raw_input("Hi! Enter Fahrenheit value, and get it in Celsius!\n"))
    except ValueError:
        print "\nYour insertion was not a digit!"
        print "We've put your Fahrenheit value to 50!"
        Fahrenheit = 50
    return Fahrenheit

def formeln(c):
    Celsius = (Fahrenheit - 32.00) * 5.00/9.00
    return Celsius

def printC(answer):
    answer = str(roundTraditional(answer,2))
    print "\nYour Celsius value is " + answer + " C.\n"

main()

…应该给您期望的结果。

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


编辑:感谢Blckknght指出,5条纹情况仅在此处的某些值出现。

You want to round your answer.

round(value,significantDigit) is the ordinary solution to do this, however this sometimes does not operate as one would expect from a math perspective when the digit immediately inferior (to the left of) the digit you’re rounding to has a 5.

Here’s some examples of this unpredictable behavior:

>>> 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

Assuming your intent is to do the traditional rounding for statistics in the sciences, this is a handy wrapper to get the round function working as expected needing to import extra stuff like Decimal.

>>> round(0.075,2)

0.07

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

0.08

Aha! So based on this we can make a function…

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

Basically this adds a really small value to the string to force it to round up properly on the unpredictable instances where it doesn’t ordinarily with the round function when you expect it to. A convenient value to add is 1e-X where X is the length of the number string you’re trying to use round on plus 1.

The approach of using 10**(-len(val)-1) was deliberate, as it the largest small number you can add to force the shift, while also ensuring that the value you add never changes the rounding even if the decimal . is missing. I could use just 10**(-len(val)) with a condiditional if (val>1) to subtract 1 more… but it’s simpler to just always subtract the 1 as that won’t change much the applicable range of decimal numbers this workaround can properly handle. This approach will fail if your values reaches the limits of the type, this will fail, but for nearly the entire range of valid decimal values it should work.

So the finished code will be something like:

def main():
    printC(formeln(typeHere()))

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

def typeHere():
    global Fahrenheit
    try:
        Fahrenheit = int(raw_input("Hi! Enter Fahrenheit value, and get it in Celsius!\n"))
    except ValueError:
        print "\nYour insertion was not a digit!"
        print "We've put your Fahrenheit value to 50!"
        Fahrenheit = 50
    return Fahrenheit

def formeln(c):
    Celsius = (Fahrenheit - 32.00) * 5.00/9.00
    return Celsius

def printC(answer):
    answer = str(roundTraditional(answer,2))
    print "\nYour Celsius value is " + answer + " C.\n"

main()

…should give you the results you expect.

You can also use the decimal library to accomplish this, but the wrapper I propose is simpler and may be preferred in some cases.


Edit: Thanks Blckknght for pointing out that the 5 fringe case occurs only for certain values here.


回答 5

只需使用%.2f的格式,它就可以四舍五入到小数点后两位。

def printC(answer):
    print "\nYour Celsius value is %.2f C.\n" % answer

Just use the formatting with %.2f which gives you rounding down to 2 decimals.

def printC(answer):
    print "\nYour Celsius value is %.2f C.\n" % answer

回答 6

您可以使用python“%”的字符串格式运算符。“%.2f”表示小数点后两位。

def typeHere():
    try:
        Fahrenheit = int(raw_input("Hi! Enter Fahrenheit value, and get it in Celsius!\n"))
    except ValueError:
        print "\nYour insertion was not a digit!"
        print "We've put your Fahrenheit value to 50!"
        Fahrenheit = 50
    return Fahrenheit

def formeln(Fahrenheit):
    Celsius = (Fahrenheit - 32.0) * 5.0/9.0
    return Celsius

def printC(answer):
    print "\nYour Celsius value is %.2f C.\n" % answer

def main():
    printC(formeln(typeHere()))

main()

http://docs.python.org/2/library/stdtypes.html#string-formatting

You can use the string formatting operator of python “%”. “%.2f” means 2 digits after the decimal point.

def typeHere():
    try:
        Fahrenheit = int(raw_input("Hi! Enter Fahrenheit value, and get it in Celsius!\n"))
    except ValueError:
        print "\nYour insertion was not a digit!"
        print "We've put your Fahrenheit value to 50!"
        Fahrenheit = 50
    return Fahrenheit

def formeln(Fahrenheit):
    Celsius = (Fahrenheit - 32.0) * 5.0/9.0
    return Celsius

def printC(answer):
    print "\nYour Celsius value is %.2f C.\n" % answer

def main():
    printC(formeln(typeHere()))

main()

http://docs.python.org/2/library/stdtypes.html#string-formatting


回答 7

您最多可以使用舍入运算符2位小数

num = round(343.5544, 2)
print(num) // output is 343.55

You can use round operator for up to 2 decimal

num = round(343.5544, 2)
print(num) // output is 343.55

回答 8

您可以使用舍入功能。

round(80.23456, 3)

会给你80.234的答案

根据您的情况使用

answer = str(round(answer, 2))

希望这可以帮助 :)

You can use the round function.

round(80.23456, 3)

will give you an answer of 80.234

In your case, use

answer = str(round(answer, 2))

回答 9

如果需要避免浮点问题在舍入数字时出现,可以使用numpy round。

您需要安装numpy:

pip install numpy

和代码:

import numpy as np

print(round(2.675, 2))
print(float(np.round(2.675, 2)))

版画

2.67
2.68

如果您通过合法的四舍五入管理资金,则应该使用该选项。

If you need avoid floating point problem on rounding numbers for accounting, you can use numpy round.

You need install numpy :

pip install numpy

and the code :

import numpy as np

print(round(2.675, 2))
print(float(np.round(2.675, 2)))

prints

2.67
2.68

You should use that if you manage money with legal rounding.


回答 10

这是我使用的示例:

def volume(self):
    return round(pi * self.radius ** 2 * self.height, 2)

def surface_area(self):
    return round((2 * pi * self.radius * self.height) + (2 * pi * self.radius ** 2), 2)

Here is an example that I used:

def volume(self):
    return round(pi * self.radius ** 2 * self.height, 2)

def surface_area(self):
    return round((2 * pi * self.radius * self.height) + (2 * pi * self.radius ** 2), 2)

回答 11

不知道为什么,但是'{:0.2f}’。format(0.5357706)给我’0.54’。唯一适用于我的解决方案(python 3.6)如下:

def ceil_floor(x):
    import math
    return math.ceil(x) if x < 0 else math.floor(x)

def round_n_digits(x, n):
    import math
    return ceil_floor(x * math.pow(10, n)) / math.pow(10, n)

round_n_digits(-0.5357706, 2) -> -0.53 
round_n_digits(0.5357706, 2) -> 0.53

Not sure why, but ‘{:0.2f}’.format(0.5357706) gives me ‘0.54’. The only solution that works for me (python 3.6) is the following:

def ceil_floor(x):
    import math
    return math.ceil(x) if x < 0 else math.floor(x)

def round_n_digits(x, n):
    import math
    return ceil_floor(x * math.pow(10, n)) / math.pow(10, n)

round_n_digits(-0.5357706, 2) -> -0.53 
round_n_digits(0.5357706, 2) -> 0.53

回答 12

因为您希望答案以十进制数字表示,所以您无需将您的答案变量类型转换为printC()函数中的str。

然后使用printf样式的字符串格式

As you want your answer in decimal number so you dont need to typecast your answer variable to str in printC() function.

and then use printf-style String Formatting


回答 13

round(12.3956 - 0.005, 2)  # minus 0.005, then round.

答案来自:https : //stackoverflow.com/a/29651462/8025086

round(12.3956 - 0.005, 2)  # minus 0.005, then round.

The answer is from: https://stackoverflow.com/a/29651462/8025086


如何在Python中四舍五入一个数字?

问题:如何在Python中四舍五入一个数字?

这个问题使我丧命。如何在Python中向上舍入一个数字?

我尝试了舍入(数字),但它四舍五入数字。例:

round(2.3) = 2.0 and not 3, what I would like

我尝试了int(number + .5),但是它再次将数字取整!例:

int(2.3 + .5) = 2

然后我尝试了round(number + .5),但在边缘情况下不起作用。例:

WAIT! THIS WORKED!

请指教。

This problem is killing me. How does one roundup a number UP in Python?

I tried round(number) but it round the number down. Example:

round(2.3) = 2.0 and not 3, what I would like

The I tried int(number + .5) but it round the number down again! Example:

int(2.3 + .5) = 2

Then I tried round(number + .5) but it won’t work in edge cases. Example:

WAIT! THIS WORKED!

Please advise.


回答 0

小区(上限)功能:

import math
print(math.ceil(4.2))

The ceil (ceiling) function:

import math
print(math.ceil(4.2))

回答 1

我知道这个答案是一个很久以前的问题,但是如果您不想导入数学并且只想四舍五入,那么这对我有用。

>>> int(21 / 5)
4
>>> int(21 / 5) + (21 % 5 > 0)
5

如果有余数,则第一部分将变为4,第二部分将得出“ True”,另外,True = 1; False =0。因此,如果没有余数,则它将保持相同的整数,但是如果有余数,则将其加1。

I know this answer is for a question from a while back, but if you don’t want to import math and you just want to round up, this works for me.

>>> int(21 / 5)
4
>>> int(21 / 5) + (21 % 5 > 0)
5

The first part becomes 4 and the second part evaluates to “True” if there is a remainder, which in addition True = 1; False = 0. So if there is no remainder, then it stays the same integer, but if there is a remainder it adds 1.


回答 2

请记住有趣的Python 2.x问题:

>>> import math
>>> math.ceil(4500/1000)
4.0
>>> math.ceil(4500/1000.0)
5.0

问题是在python中将两个int相除会产生另一个int,并且在上限调用之前被截断了。您必须使一个值成为浮点数(或强制转换)才能获得正确的结果。

在javascript中,完全相同的代码会产生不同的结果:

console.log(Math.ceil(4500/1000));
5

Interesting Python 2.x issue to keep in mind:

>>> import math
>>> math.ceil(4500/1000)
4.0
>>> math.ceil(4500/1000.0)
5.0

The problem is that dividing two ints in python produces another int and that’s truncated before the ceiling call. You have to make one value a float (or cast) to get a correct result.

In javascript, the exact same code produces a different result:

console.log(Math.ceil(4500/1000));
5

回答 3

如果使用整数,则四舍五入的一种方法是利用四舍五入的事实//:只需对负数进行除法,然后取反即可。无需导入,浮点或有条件的。

rounded_up = -(-numerator // denominator)

例如:

>>> print(-(-101 // 5))
21

If working with integers, one way of rounding up is to take advantage of the fact that // rounds down: Just do the division on the negative number, then negate the answer. No import, floating point, or conditional needed.

rounded_up = -(-numerator // denominator)

For example:

>>> print(-(-101 // 5))
21

回答 4

您可能还喜欢numpy:

>>> import numpy as np
>>> np.ceil(2.3)
3.0

我并不是说它比数学更好,但是如果您已经将numpy用于其他目的,则可以使代码保持一致。

无论如何,我遇到的只是一个细节。我经常使用numpy,但感到惊讶的是它没有被提及,但是当然可以接受。

You might also like numpy:

>>> import numpy as np
>>> np.ceil(2.3)
3.0

I’m not saying it’s better than math, but if you were already using numpy for other purposes, you can keep your code consistent.

Anyway, just a detail I came across. I use numpy a lot and was surprised it didn’t get mentioned, but of course the accepted answer works perfectly fine.


回答 5

使用math.ceil围捕:

>>> import math
>>> math.ceil(5.4)
6.0

注意:输入应为浮点型。

如果需要整数,请调用int将其转换:

>>> int(math.ceil(5.4))
6

BTW,使用math.floor到轮,并round以轮最接近的整数。

>>> math.floor(4.4), math.floor(4.5), math.floor(5.4), math.floor(5.5)
(4.0, 4.0, 5.0, 5.0)
>>> round(4.4), round(4.5), round(5.4), round(5.5)
(4.0, 5.0, 5.0, 6.0)
>>> math.ceil(4.4), math.ceil(4.5), math.ceil(5.4), math.ceil(5.5)
(5.0, 5.0, 6.0, 6.0)

Use math.ceil to round up:

>>> import math
>>> math.ceil(5.4)
6.0

NOTE: The input should be float.

If you need an integer, call int to convert it:

>>> int(math.ceil(5.4))
6

BTW, use math.floor to round down and round to round to nearest integer.

>>> math.floor(4.4), math.floor(4.5), math.floor(5.4), math.floor(5.5)
(4.0, 4.0, 5.0, 5.0)
>>> round(4.4), round(4.5), round(5.4), round(5.5)
(4.0, 5.0, 5.0, 6.0)
>>> math.ceil(4.4), math.ceil(4.5), math.ceil(5.4), math.ceil(5.5)
(5.0, 5.0, 6.0, 6.0)

回答 6

语法可能不像pythonic那样,但是它是一个功能强大的库。

https://docs.python.org/2/library/decimal.html

from decimal import *
print(int(Decimal(2.3).quantize(Decimal('1.'), rounding=ROUND_UP)))

The syntax may not be as pythonic as one might like, but it is a powerful library.

https://docs.python.org/2/library/decimal.html

from decimal import *
print(int(Decimal(2.3).quantize(Decimal('1.'), rounding=ROUND_UP)))

回答 7

我很惊讶没有人建议

(numerator + denominator - 1) // denominator

用于四舍五入的整数除法。曾经是C / C ++ / CUDA的常用方法(参见divup

I am surprised nobody suggested

(numerator + denominator - 1) // denominator

for integer division with rounding up. Used to be the common way for C/C++/CUDA (cf. divup)


回答 8

请确保四舍五入的值应为浮点型

a = 8 
b = 21
print math.ceil(a / b)
>>> 0

print math.ceil(float(a) / b)
>>> 1.0

Be shure rounded value should be float

a = 8 
b = 21
print math.ceil(a / b)
>>> 0

but

print math.ceil(float(a) / b)
>>> 1.0

回答 9

尝试这个:

a = 211.0
print(int(a) + ((int(a) - a) != 0))

Try this:

a = 211.0
print(int(a) + ((int(a) - a) != 0))

回答 10

>>> def roundup(number):
...     return round(number+.5)
>>> roundup(2.3)
3
>>> roundup(19.00000000001)
20

此功能不需要任何模块。

>>> def roundup(number):
...     return round(number+.5)
>>> roundup(2.3)
3
>>> roundup(19.00000000001)
20

This function requires no modules.


回答 11

上面的答案是正确的,但是,math对于这个功能而言,导入模块通常对我来说有点过头了。幸运的是,还有另一种方法可以做到:

g = 7/5
g = int(g) + (not g.is_integer())

True并且在python中涉及数字的语句中False被解释为10g.is_interger()基本上翻译为g.has_no_decimal()g == int(g)。因此,最后的英文陈述为round g down and add one if g has decimal

The above answers are correct, however, importing the math module just for this one function usually feels like a bit of an overkill for me. Luckily, there is another way to do it:

g = 7/5
g = int(g) + (not g.is_integer())

True and False are interpreted as 1 and 0 in a statement involving numbers in python. g.is_interger() basically translates to g.has_no_decimal() or g == int(g). So the last statement in English reads round g down and add one if g has decimal.


回答 12

无需导入数学//使用基本环境:

a)方法/类方法

def ceil(fl): 
  return int(fl) + (1 if fl-int(fl) else 0)

def ceil(self, fl): 
  return int(fl) + (1 if fl-int(fl) else 0)

b)lambda:

ceil = lambda fl:int(fl)+(1 if fl-int(fl) else 0)

Without importing math // using basic envionment:

a) method / class method

def ceil(fl): 
  return int(fl) + (1 if fl-int(fl) else 0)

def ceil(self, fl): 
  return int(fl) + (1 if fl-int(fl) else 0)

b) lambda:

ceil = lambda fl:int(fl)+(1 if fl-int(fl) else 0)

回答 13

对于那些想要四舍五入a / b并获得整数的人:

使用整数除法的另一个变体是

def int_ceil(a, b):
    return (a - 1) // b + 1

>>> int_ceil(19, 5)
4
>>> int_ceil(20, 5)
4
>>> int_ceil(21, 5)
5

For those who want to round up a / b and get integer:

Another variant using integer division is

def int_ceil(a, b):
    return (a - 1) // b + 1

>>> int_ceil(19, 5)
4
>>> int_ceil(20, 5)
4
>>> int_ceil(21, 5)
5

回答 14

如果有人希望将其舍入到小数点后一位:

import math
def round_up(n, decimals=0):
    multiplier = 10 ** decimals
    return math.ceil(n * multiplier) / multiplier

In case anyone is looking to round up to a specific decimal place:

import math
def round_up(n, decimals=0):
    multiplier = 10 ** decimals
    return math.ceil(n * multiplier) / multiplier

回答 15

令我惊讶的是我还没有看到这个答案round(x + 0.4999),所以我要把它放下来。请注意,这适用于任何Python版本。对Python舍入方案的更改使事情变得困难。看到这篇文章

不导入,我使用:

def roundUp(num):
    return round(num + 0.49)

testCases = list(x*0.1 for x in range(0, 50))

print(testCases)
for test in testCases:
    print("{:5.2f}  -> {:5.2f}".format(test, roundUp(test)))

为什么这样

来自文档

对于支持round()的内置类型,将值四舍五入为乘幂n的最接近10的倍数;如果两个倍数相等接近,则四舍五入取整为偶数选择

因此,将2.5舍入为2,将3.5舍入为4。如果不是这种情况,则可以通过加0.5来舍入,但是我们要避免到达中间点。因此,如果添加0.4999,您将接近,但有足够的余量可以四舍五入到通常的期望值。当然,如果x + 0.4999等于,这将失败[n].5000,但这不太可能。

I’m surprised I haven’t seen this answer yet round(x + 0.4999), so I’m going to put it down. Note that this works with any Python version. Changes made to the Python rounding scheme has made things difficult. See this post.

Without importing, I use:

def roundUp(num):
    return round(num + 0.49)

testCases = list(x*0.1 for x in range(0, 50))

print(testCases)
for test in testCases:
    print("{:5.2f}  -> {:5.2f}".format(test, roundUp(test)))

Why this works

From the docs

For the built-in types supporting round(), values are rounded to the closest multiple of 10 to the power minus n; if two multiples are equally close, rounding is done toward the even choice

Therefore 2.5 gets rounded to 2 and 3.5 gets rounded to 4. If this was not the case then rounding up could be done by adding 0.5, but we want to avoid getting to the halfway point. So, if you add 0.4999 you will get close, but with enough margin to be rounded to what you would normally expect. Of course, this will fail if the x + 0.4999 is equal to [n].5000, but that is unlikely.


回答 16

要做到这一点而无需任何导入:

>>> round_up = lambda num: int(num + 1) if int(num) != num else int(num)
>>> round_up(2.0)
2
>>> round_up(2.1)
3

To do it without any import:

>>> round_up = lambda num: int(num + 1) if int(num) != num else int(num)
>>> round_up(2.0)
2
>>> round_up(2.1)
3

回答 17

我知道这已经有一段时间了,但是我找到了一个非常有趣的答案,所以可以这样:

-round(-x-0.5)

这可以修复边缘情况,并且适用于正数和负数,并且不需要任何函数导入

干杯

I know this is from quite a while back, but I found a quite interesting answer, so here goes:

-round(-x-0.5)

This fixes the edges cases and works for both positive and negative numbers, and doesn’t require any function import

Cheers


回答 18

当您在python中操作4500/1000时,结果将为4,因为默认情况下python假定结果为整数,逻辑上:4500/1000 = 4.5-> int(4.5)= 4且ceil显然为4

使用4500 / 40.0的结果将是4.5且ceil为4.5-> 5

使用javascript,您将收到4.5的4500/1000结果,因为javascript仅将结果视为“数值类型”,并将结果直接返回为float

祝好运!!

when you operate 4500/1000 in python, result will be 4, because for default python asume as integer the result, logically: 4500/1000 = 4.5 –> int(4.5) = 4 and ceil of 4 obviouslly is 4

using 4500/1000.0 the result will be 4.5 and ceil of 4.5 –> 5

Using javascript you will recieve 4.5 as result of 4500/1000, because javascript asume only the result as “numeric type” and return a result directly as float

Good Luck!!


回答 19

如果您不想导入任何内容,则可以始终将自己的简单函数编写为:

def RoundUP(num): if num== int(num): return num return int(num + 1)

If you don’t want to import anything, you can always write your own simple function as:

def RoundUP(num): if num== int(num): return num return int(num + 1)


回答 20

您可以使用楼层划分并将其添加1。2.3 // 2 + 1

You can use floor devision and add 1 to it. 2.3 // 2 + 1


回答 21

我认为您会混淆int()和之间的工作机制round()

int()如果给出浮点数,则总是截断十进制数;相反round(),如果2.5where 23are都在等距离内2.5,则Python返回距离0点更远的那个。

round(2.5) = 3
int(2.5) = 2

I think you are confusing the working mechanisms between int() and round().

int() always truncates the decimal numbers if a floating number is given; whereas round(), in case of 2.5 where 2 and 3 are both within equal distance from 2.5, Python returns whichever that is more away from the 0 point.

round(2.5) = 3
int(2.5) = 2

回答 22

我的份额

我已经测试 print(-(-101 // 5)) = 21了上面给出的示例。

现在进行四舍五入:

101 * 19% = 19.19

我不能使用,**所以我将乘法扩展到除法:

(-(-101 //(1/0.19))) = 20

My share

I have tested print(-(-101 // 5)) = 21 given example above.

Now for rounding up:

101 * 19% = 19.19

I can not use ** so I spread the multiply to division:

(-(-101 //(1/0.19))) = 20

回答 23

我基本上是Python的初学者,但是如果您只是想舍入而不是舍弃,那为什么不做:

round(integer) + 1

I’m basically a beginner at Python, but if you’re just trying to round up instead of down why not do:

round(integer) + 1

将浮点数限制为两位小数

问题:将浮点数限制为两位小数

我想a四舍五入到13.95

>>> a
13.949999999999999
>>> round(a, 2)
13.949999999999999

round功能无法按我预期的方式工作。

I want a to be rounded to 13.95.

>>> a
13.949999999999999
>>> round(a, 2)
13.949999999999999

The round function does not work the way I expected.


回答 0

您正在碰到浮点数的旧问题,即并非所有数字都可以准确表示。命令行只是向您显示内存中的完整浮点形式。

使用浮点表示法,您的舍入版本为相同的数字。由于计算机是二进制的,因此它们将浮点数存储为整数,然后将其除以2的幂,因此将以与125650429603636838 /(2 ** 53)相似的方式表示13.95。

双精度数字的精度为53位(16位),常规浮点数的精度为24位(8位)。Python中浮点类型使用双精度来存储值。

例如,

>>> 125650429603636838/(2**53)
13.949999999999999

>>> 234042163/(2**24)
13.949999988079071

>>> a = 13.946
>>> print(a)
13.946
>>> print("%.2f" % a)
13.95
>>> round(a,2)
13.949999999999999
>>> print("%.2f" % round(a, 2))
13.95
>>> print("{:.2f}".format(a))
13.95
>>> print("{:.2f}".format(round(a, 2)))
13.95
>>> print("{:.15f}".format(round(a, 2)))
13.949999999999999

如果仅排两个小数位(例如,显示货币值),则有两个更好的选择:

  1. 使用整数并以美分而不是美元存储值,然后除以100转换为美元。
  2. 或者使用定点数(如小数)

You are running into the old problem with floating point numbers that not all numbers can be represented exactly. The command line is just showing you the full floating point form from memory.

With floating point representation, your rounded version is the same number. Since computers are binary, they store floating point numbers as an integer and then divide it by a power of two so 13.95 will be represented in a similar fashion to 125650429603636838/(2**53).

Double precision numbers have 53 bits (16 digits) of precision and regular floats have 24 bits (8 digits) of precision. The floating point type in Python uses double precision to store the values.

For example,

>>> 125650429603636838/(2**53)
13.949999999999999

>>> 234042163/(2**24)
13.949999988079071

>>> a = 13.946
>>> print(a)
13.946
>>> print("%.2f" % a)
13.95
>>> round(a,2)
13.949999999999999
>>> print("%.2f" % round(a, 2))
13.95
>>> print("{:.2f}".format(a))
13.95
>>> print("{:.2f}".format(round(a, 2)))
13.95
>>> print("{:.15f}".format(round(a, 2)))
13.949999999999999

If you are after only two decimal places (to display a currency value, for example), then you have a couple of better choices:

  1. Use integers and store values in cents, not dollars and then divide by 100 to convert to dollars.
  2. Or use a fixed point number like decimal.

回答 1

有新的格式规范,字符串格式规范迷你语言

您可以执行以下操作:

"{:.2f}".format(13.949999999999999)

注1:以上返回一个字符串。为了获得浮点数,只需用包装float(...)

float("{:.2f}".format(13.949999999999999))

注意2:包裹float()不会改变任何内容:

>>> x = 13.949999999999999999
>>> x
13.95
>>> g = float("{:.2f}".format(x))
>>> g
13.95
>>> x == g
True
>>> h = round(x, 2)
>>> h
13.95
>>> x == h
True

There are new format specifications, String Format Specification Mini-Language:

You can do the same as:

"{:.2f}".format(13.949999999999999)

Note 1: the above returns a string. In order to get as float, simply wrap with float(...):

float("{:.2f}".format(13.949999999999999))

Note 2: wrapping with float() doesn’t change anything:

>>> x = 13.949999999999999999
>>> x
13.95
>>> g = float("{:.2f}".format(x))
>>> g
13.95
>>> x == g
True
>>> h = round(x, 2)
>>> h
13.95
>>> x == h
True

回答 2

内建round()在Python 2.7或更高版本中工作正常。

例:

>>> round(14.22222223, 2)
14.22

查看文档

The built-in round() works just fine in Python 2.7 or later.

Example:

>>> round(14.22222223, 2)
14.22

Check out the documentation.


回答 3

我觉得最简单的方法是使用format()函数。

例如:

a = 13.949999999999999
format(a, '.2f')

13.95

这将产生一个浮点数作为四舍五入到小数点后两位的字符串。

I feel that the simplest approach is to use the format() function.

For example:

a = 13.949999999999999
format(a, '.2f')

13.95

This produces a float number as a string rounded to two decimal points.


回答 4

采用

print"{:.2f}".format(a)

代替

print"{0:.2f}".format(a)

因为后者在尝试输出多个变量时可能会导致输出错误(请参见注释)。

Use

print"{:.2f}".format(a)

instead of

print"{0:.2f}".format(a)

Because the latter may lead to output errors when trying to output multiple variables (see comments).


回答 5

大多数数字不能用浮点数精确表示。如果要舍入该数字,因为这是您的数学公式或算法所需要的,那么您要使用舍入。如果您只想限制显示的精度,甚至不用舍入,只需将其格式化为该字符串即可。(如果要用其他替代的四舍五入方法显示它,并且有很多吨,则需要将两种方法混合使用。)

>>> "%.2f" % 3.14159
'3.14'
>>> "%.2f" % 13.9499999
'13.95'

最后,虽然也许是最重要的一点,但是如果您想要精确的数学运算,那么根本就不需要浮点数。通常的例子是处理货币并将“分”存储为整数。

Most numbers cannot be exactly represented in floats. If you want to round the number because that’s what your mathematical formula or algorithm requires, then you want to use round. If you just want to restrict the display to a certain precision, then don’t even use round and just format it as that string. (If you want to display it with some alternate rounding method, and there are tons, then you need to mix the two approaches.)

>>> "%.2f" % 3.14159
'3.14'
>>> "%.2f" % 13.9499999
'13.95'

And lastly, though perhaps most importantly, if you want exact math then you don’t want floats at all. The usual example is dealing with money and to store ‘cents’ as an integer.


回答 6

请尝试以下代码:

>>> a = 0.99334
>>> a = int((a * 100) + 0.5) / 100.0 # Adding 0.5 rounds it up
>>> print a
0.99

Try the code below:

>>> a = 0.99334
>>> a = int((a * 100) + 0.5) / 100.0 # Adding 0.5 rounds it up
>>> print a
0.99

回答 7

TLDR;)

输入/输出的舍入问题已由Python 2.7.03.1 彻底解决

正确舍入的数字可以可逆地来回转换:
str -> float() -> repr() -> float() ...Decimal -> float -> str -> Decimal
不再需要使用十进制类型存储。


(自然地,可能有必要对舍入后的数字进行加或减运算,以消除累积的最后一位误码。显式的十进制算术仍然很方便,但是转换为字符串的方式是str()(即舍入到12个有效数字)通常足够好,如果不需要极高的精度或不需要极大量的连续算术运算。)

无限测试

import random
from decimal import Decimal
for x in iter(random.random, None):           # Verify FOREVER that rounding is fixed :-)
    assert float(repr(x)) == x                # Reversible repr() conversion.
    assert float(Decimal(repr(x))) == x
    assert len(repr(round(x, 10))) <= 12      # Smart decimal places in repr() after round.
    if x >= 0.1:                              # Implicit rounding to 12 significant digits
        assert str(x) == repr(round(x, 12))   # by str() is good enough for small errors.
        y = 1000 * x                             # Decimal type is excessive for shopping
        assert str(y) == repr(round(y, 12 - 3))  # in a supermaket with Python 2.7+ :-)

文献资料

请参阅发行说明Python 2.7-其他语言更改的第四段:

现在在大多数平台上都可以正确舍入浮点数和字符串之间的转换。这些转换发生在许多不同的地方:str()代表浮点数和复数;浮动和复杂的构造函数;数字格式;串行化,并使用反序列浮子和复数marshalpicklejson模块; 在Python代码中解析float和虚数文字;和十进制到浮点转换。

与此相关的是,浮点数x 的repr()现在基于最短的十进制字符串返回一个结果,该字符串保证在正确的舍入(使用“从一半到一半到四舍五入的舍入模式”下)可以四舍五入为x。以前,它根据x舍入到17个十进制数字给出了一个字符串。

相关问题


详细信息:float Python 2.7之前的格式与当前相似numpy.float64。两种类型都使用相同的64位IEEE 754双精度和52位尾数。一个很大的不同是,np.float64.__repr__经常使用过多的十进制数字进行格式化,以便不会丢失任何位,但是在13.949999999999999和13.950000000000001之间不存在有效的IEEE 754数字。结果不是很好,并且repr(float(number_as_string))使用numpy无法进行转换。另一方面:float.__repr__格式化,以便每个数字都很重要;顺序没有间隙,转换是可逆的。简单:如果您有一个numpy.float64数字,请将其转换为普通float,以便为人类(而非数字处理器)格式化,否则Python 2.7+不再需要。

TLDR 😉

The rounding problem of input / output has been solved definitively by Python 2.7.0 and 3.1.

A correctly rounded number can be reversibly converted back and forth:
str -> float() -> repr() -> float() ... or Decimal -> float -> str -> Decimal
A Decimal type is not necessary for storage anymore.


(Naturally, it can be necessary to round a result of addition or subtraction of rounded numbers to eliminate the accumulated last bit errors. An explicit Decimal arithmetic can be still handy, but a conversion to string by str() (that is with rounding to 12 valid digits) is good enough usually if no extreme accuracy or no extreme number of successive arithmetic operations is required.)

Infinite test:

import random
from decimal import Decimal
for x in iter(random.random, None):           # Verify FOREVER that rounding is fixed :-)
    assert float(repr(x)) == x                # Reversible repr() conversion.
    assert float(Decimal(repr(x))) == x
    assert len(repr(round(x, 10))) <= 12      # Smart decimal places in repr() after round.
    if x >= 0.1:                              # Implicit rounding to 12 significant digits
        assert str(x) == repr(round(x, 12))   # by str() is good enough for small errors.
        y = 1000 * x                             # Decimal type is excessive for shopping
        assert str(y) == repr(round(y, 12 - 3))  # in a supermaket with Python 2.7+ :-)

Documentation

See the Release notes Python 2.7 – Other Language Changes the fourth paragraph:

Conversions between floating-point numbers and strings are now correctly rounded on most platforms. These conversions occur in many different places: str() on floats and complex numbers; the float and complex constructors; numeric formatting; serializing and de-serializing floats and complex numbers using the marshal, pickle and json modules; parsing of float and imaginary literals in Python code; and Decimal-to-float conversion.

Related to this, the repr() of a floating-point number x now returns a result based on the shortest decimal string that’s guaranteed to round back to x under correct rounding (with round-half-to-even rounding mode). Previously it gave a string based on rounding x to 17 decimal digits.

The related issue


More information: The formatting of float before Python 2.7 was similar to the current numpy.float64. Both types use the same 64 bit IEEE 754 double precision with 52 bit mantissa. A big difference is that np.float64.__repr__ is formatted frequently with an excessive decimal number so that no bit can be lost, but no valid IEEE 754 number exists between 13.949999999999999 and 13.950000000000001. The result is not nice and the conversion repr(float(number_as_string)) is not reversible with numpy. On the other hand: float.__repr__ is formatted so that every digit is important; the sequence is without gaps and the conversion is reversible. Simply: If you perhaps have a numpy.float64 number, convert it to normal float in order to be formatted for humans, not for numeric processors, otherwise nothing more is necessary with Python 2.7+.


回答 8

使用Python <3(例如2.6或2.7),有两种方法。

# Option one 
older_method_string = "%.9f" % numvar

# Option two (note ':' before the '.9f')
newer_method_string = "{:.9f}".format(numvar)

但请注意,对于高于3的Python版本(例如3.2或3.3),首选选项2 。

有关选项二的更多信息,我建议使用Python文档中有关字符串格式的链接。

有关选项一的更多信息,此链接就足够了,并且具有有关各种标志的信息

参考:将浮点数转换为一定精度,然后复制到字符串

With Python < 3 (e.g. 2.6 or 2.7), there are two ways to do so.

# Option one 
older_method_string = "%.9f" % numvar

# Option two (note ':' before the '.9f')
newer_method_string = "{:.9f}".format(numvar)

But note that for Python versions above 3 (e.g. 3.2 or 3.3), option two is preferred.

For more information on option two, I suggest this link on string formatting from the Python documentation.

And for more information on option one, this link will suffice and has information on the various flags.

Reference: Convert floating point number to a certain precision, and then copy to string


回答 9

您可以修改输出格式:

>>> a = 13.95
>>> a
13.949999999999999
>>> print "%.2f" % a
13.95

You can modify the output format:

>>> a = 13.95
>>> a
13.949999999999999
>>> print "%.2f" % a
13.95

回答 10

这里似乎还没有人提到它,所以让我举一个Python 3.6的f-string / template-string格式的例子,我认为它很简洁:

>>> f'{a:.2f}'

它也适用于较长的示例,不需要运算符,也不需要运算符:

>>> print(f'Completed in {time.time() - start:.2f}s')

Nobody here seems to have mentioned it yet, so let me give an example in Python 3.6’s f-string/template-string format, which I think is beautifully neat:

>>> f'{a:.2f}'

It works well with longer examples too, with operators and not needing parens:

>>> print(f'Completed in {time.time() - start:.2f}s')

回答 11

您可以使用格式运算符将值四舍五入到python中的小数点后2位:

print(format(14.4499923, '.2f')) // output is 14.45

You can use format operator for rounding the value up to 2 decimal places in python:

print(format(14.4499923, '.2f')) // output is 14.45

回答 12

在Python 2.7中:

a = 13.949999999999999
output = float("%0.2f"%a)
print output

In Python 2.7:

a = 13.949999999999999
output = float("%0.2f"%a)
print output

回答 13

Python教程有一个附录,称为“ 浮点算术:问题和局限性”。阅读。它解释了正在发生的事情以及Python尽其所能的原因。它甚至有一个与您匹配的示例。让我引用一下:

>>> 0.1
0.10000000000000001

您可能会想使用该round() 函数将其切回到您期望的个位数。但这没有什么区别:

>>> round(0.1, 1)
0.10000000000000001

问题在于,存储的的二进制浮点值“0.1” 已经是与的最佳可能的二进制近似值。1/10,因此尝试再次对其进行舍入并不能使它更好:它已经足够好了。

另一个结果是,由于0.1 不完全精确1/10,将的十个值相加0.1可能不会精确地产生 1.0,或者:

>>> sum = 0.0
>>> for i in range(10):
...     sum += 0.1
...
>>> sum
0.99999999999999989

解决该问题的一种方法是使用该decimal模块。

The Python tutorial has an appendix called Floating Point Arithmetic: Issues and Limitations. Read it. It explains what is happening and why Python is doing its best. It has even an example that matches yours. Let me quote a bit:

>>> 0.1
0.10000000000000001

you may be tempted to use the round() function to chop it back to the single digit you expect. But that makes no difference:

>>> round(0.1, 1)
0.10000000000000001

The problem is that the binary floating-point value stored for “0.1” was already the best possible binary approximation to 1/10, so trying to round it again can’t make it better: it was already as good as it gets.

Another consequence is that since 0.1 is not exactly 1/10, summing ten values of 0.1 may not yield exactly 1.0, either:

>>> sum = 0.0
>>> for i in range(10):
...     sum += 0.1
...
>>> sum
0.99999999999999989

One alternative and solution to your problems would be using the decimal module.


回答 14

正如@Matt所指出的,Python 3.6提供了f-strings,它们也可以使用嵌套参数

value = 2.34558
precision = 2
width = 4

print(f'result: {value:{width}.{precision}f}')

将显示 result: 2.35

As @Matt pointed out, Python 3.6 provides f-strings, and they can also use nested parameters:

value = 2.34558
precision = 2
width = 4

print(f'result: {value:{width}.{precision}f}')

which will display result: 2.35


回答 15

它完全按照您的要求做,并且工作正常。阅读有关浮点混淆的更多信息,或者尝试使用十进制对象。

It’s doing exactly what you told it to do and is working correctly. Read more about floating point confusion and maybe try decimal objects instead.


回答 16

结合使用Decimal对象和round()方法。

Python 3.7.3
>>> from decimal import Decimal
>>> d1 = Decimal (13.949999999999999) # define a Decimal
>>> d1 
Decimal('13.949999999999999289457264239899814128875732421875')
>>> d2 = round(d1, 2) # round to 2 decimals
>>> d2
Decimal('13.95')

Use combination of Decimal object and round() method.

Python 3.7.3
>>> from decimal import Decimal
>>> d1 = Decimal (13.949999999999999) # define a Decimal
>>> d1 
Decimal('13.949999999999999289457264239899814128875732421875')
>>> d2 = round(d1, 2) # round to 2 decimals
>>> d2
Decimal('13.95')

回答 17

为了固定类型动态语言(例如Python和JavaScript)中的浮点,我使用了这种技术

# For example:
a = 70000
b = 0.14
c = a * b

print c # Prints 980.0000000002
# Try to fix
c = int(c * 10000)/100000
print c # Prints 980

您还可以按以下方式使用Decimal:

from decimal import *
getcontext().prec = 6
Decimal(1) / Decimal(7)
# Results in 6 precision -> Decimal('0.142857')

getcontext().prec = 28
Decimal(1) / Decimal(7)
# Results in 28 precision -> Decimal('0.1428571428571428571428571429')

For fixing the floating point in type-dynamic languages such as Python and JavaScript, I use this technique

# For example:
a = 70000
b = 0.14
c = a * b

print c # Prints 980.0000000002
# Try to fix
c = int(c * 10000)/100000
print c # Prints 980

You can also use Decimal as following:

from decimal import *
getcontext().prec = 6
Decimal(1) / Decimal(7)
# Results in 6 precision -> Decimal('0.142857')

getcontext().prec = 28
Decimal(1) / Decimal(7)
# Results in 28 precision -> Decimal('0.1428571428571428571428571429')

回答 18

from decimal import Decimal


def round_float(v, ndigits=2, rt_str=False):
    d = Decimal(v)
    v_str = ("{0:.%sf}" % ndigits).format(round(d, ndigits))
    if rt_str:
        return v_str
    return Decimal(v_str)

结果:

Python 3.6.1 (default, Dec 11 2018, 17:41:10)
>>> round_float(3.1415926)
Decimal('3.14')
>>> round_float(3.1445926)
Decimal('3.14')
>>> round_float(3.1455926)
Decimal('3.15')
>>> round_float(3.1455926, rt_str=True)
'3.15'
>>> str(round_float(3.1455926))
'3.15'
from decimal import Decimal


def round_float(v, ndigits=2, rt_str=False):
    d = Decimal(v)
    v_str = ("{0:.%sf}" % ndigits).format(round(d, ndigits))
    if rt_str:
        return v_str
    return Decimal(v_str)

Results:

Python 3.6.1 (default, Dec 11 2018, 17:41:10)
>>> round_float(3.1415926)
Decimal('3.14')
>>> round_float(3.1445926)
Decimal('3.14')
>>> round_float(3.1455926)
Decimal('3.15')
>>> round_float(3.1455926, rt_str=True)
'3.15'
>>> str(round_float(3.1455926))
'3.15'

回答 19

orig_float = 232569 / 16000.0

14.5355625

short_float = float("{:.2f}".format(orig_float)) 

14.54

orig_float = 232569 / 16000.0

14.5355625

short_float = float("{:.2f}".format(orig_float)) 

14.54


回答 20

像这样的lambda函数呢?

arred = lambda x,n : x*(10**n)//1/(10**n)

这样,您可以执行以下操作:

arred(3.141591657,2)

并得到

3.14

What about a lambda function like this:

arred = lambda x,n : x*(10**n)//1/(10**n)

This way you could just do:

arred(3.141591657,2)

and get

3.14

回答 21

就像1,2,3一样简单:

  1. 十进制模块进行快速正确舍入的十进制浮点运算:

    d =十进制(10000000.0000009)

实现四舍五入:

   d.quantize(Decimal('0.01'))

将与 Decimal('10000000.00')

  1. 使以上干燥:
    def round_decimal(number, exponent='0.01'):
        decimal_value = Decimal(number)
        return decimal_value.quantize(Decimal(exponent))

要么

    def round_decimal(number, decimal_places=2):
        decimal_value = Decimal(number)
        return decimal_value.quantize(Decimal(10) ** -decimal_places)
  1. 支持这个答案:)

PS:对他人的批评:格式不是四舍五入。

It’s simple like 1,2,3:

  1. use decimal module for fast correctly-rounded decimal floating point arithmetic:

    d=Decimal(10000000.0000009)

to achieve rounding:

   d.quantize(Decimal('0.01'))

will results with Decimal('10000000.00')

  1. make above DRY:
    def round_decimal(number, exponent='0.01'):
        decimal_value = Decimal(number)
        return decimal_value.quantize(Decimal(exponent))

OR

    def round_decimal(number, decimal_places=2):
        decimal_value = Decimal(number)
        return decimal_value.quantize(Decimal(10) ** -decimal_places)
  1. upvote this answer 🙂

PS: critique of others: formatting is not rounding.


回答 22

要将数字四舍五入为一种分辨率,最好的方法是使用以下方法,该方法可以在任何分辨率下工作(0.01表示两位小数,甚至其他步长):

>>> import numpy as np
>>> value = 13.949999999999999
>>> resolution = 0.01
>>> newValue = int(np.round(value/resolution))*resolution
>>> print newValue
13.95

>>> resolution = 0.5
>>> newValue = int(np.round(value/resolution))*resolution
>>> print newValue
14.0

To round a number to a resolution, the best way is the following one, which can work with any resolution (0.01 for two decimals or even other steps):

>>> import numpy as np
>>> value = 13.949999999999999
>>> resolution = 0.01
>>> newValue = int(np.round(value/resolution))*resolution
>>> print newValue
13.95

>>> resolution = 0.5
>>> newValue = int(np.round(value/resolution))*resolution
>>> print newValue
14.0

回答 23

lambda x,n:int(x * 10 n + .5)/ 10 n已经为我使用多种语言提供多年的服务。

lambda x,n:int(x*10n+.5)/10n has worked for me for many years in many languages.


回答 24

我使用的方法是字符串切片。它相对简单快捷。

首先,将float转换为字符串,然后选择所需的长度。

float = str(float)[:5]

在上面的单行中,我们已将值转换为字符串,然后仅将字符串保留为其前四个数字或字符(包括首尾四个数字)。

希望有帮助!

The method I use is that of string slicing. It’s relatively quick and simple.

First, convert the float to a string, the choose the length you would like it to be.

float = str(float)[:5]

In the single line above, we’ve converted the value to a string, then kept the string only to its first four digits or characters (inclusive).

Hope that helps!