如何在 Python 中将数字四舍五入为有效数字
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3410976/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to round a number to significant figures in Python
提问by Peter Graham
I need to round a float to be displayed in a UI. E.g, to one significant figure:
我需要舍入要在 UI 中显示的浮点数。例如,对于一位有效数字:
1234 -> 1000
1234 -> 1000
0.12 -> 0.1
0.12 -> 0.1
0.012 -> 0.01
0.012 -> 0.01
0.062 -> 0.06
0.062 -> 0.06
6253 -> 6000
6253 -> 6000
1999 -> 2000
1999 -> 2000
Is there a nice way to do this using the Python library, or do I have to write it myself?
是否有使用 Python 库的好方法,或者我必须自己编写它?
采纳答案by Evgeny
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,您可能需要注意将浮点数转换为整数。
回答by Tim McNamara
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.
整数更棘手。它们不是以 10 为基数存储在内存中,因此重要的地方不是很自然的事情。不过,一旦它们是一个字符串,实现起来就相当简单了。
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 Decimalobjects:
另一种选择是检查类型。这将不那么灵活,并且可能无法很好地与其他数字(例如Decimal对象)配合使用:
>>> def roundall2(n, sigfigs):
... if type(n) is int: return intround(n, sigfigs)
... else: return round(n, sigfigs)
回答by Peter Graham
%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.
字符串格式中的 %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'
回答by indgar
If you want to have other than 1 significant decimal (otherwise the same as Evgeny):
如果您想拥有 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
回答by Cris Stringfellow
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.
要将整数四舍五入为 1 位有效数字,基本思想是将其转换为在该点前有 1 位数字的浮点数并四舍五入,然后将其转换回其原始整数大小。
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.
为此,我们需要知道小于整数的 10 的最大幂。为此,我们可以使用 log 10 函数的 floor。
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)
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)
回答by ryan281
I modified indgar's solution to handle negative numbers and small numbers (including zero).
我修改了 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)
回答by AJP
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:
希望能充分利用上述所有答案(减去能够将其作为一行 lambda ;) )。尚未探索,请随时编辑此答案:
round_to_n(1e15 + 1, 11) # 999999999999999.9
回答by William Rusnack
I have created the package to-precisionthat 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:
这实际上指定了 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'
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'
回答by drew.ray
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))
回答by eddygeek
Using python 2.6+ new-style formatting(as %-style is deprecated):
使用 python 2.6+新样式格式(因为 %-style 已弃用):
>>> "{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.
在 python 2.7+ 中,您可以省略前导0s。

