我需要四舍五入才能在UI中显示。例如,一个重要的数字:
1234-> 1000
0.12-> 0.1
0.012-> 0.01
0.062-> 0.06
6253-> 6000
1999-> 2000
是否有使用Python库执行此操作的好方法,还是我必须自己编写它?
我需要四舍五入才能在UI中显示。例如,一个重要的数字:
1234-> 1000
0.12-> 0.1
0.012-> 0.01
0.062-> 0.06
6253-> 6000
1999-> 2000
是否有使用Python库执行此操作的好方法,还是我必须自己编写它?
Answers:
您可以使用负数舍入整数:
>>> 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转换为整数。
log10
是确定如何舍入的唯一正确方法。
log10(abs(x))
,否则负数将失败(并且x == 0
当然要分开对待)
round_to_n = lambda x, n: x if x == 0 else round(x, -int(math.floor(math.log10(abs(x)))) + (n - 1))
防范x==0
并x<0
感谢@RoyHyunjinHan和@TobiasKienzler。不能防止未定义的内容(例如math.inf)或垃圾(例如“无”等)
字符串格式的%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'
0.075
为0.08
。它返回0.07
。
round_sig = lambda f,p: float(('%.' + str(p) + 'e') % f)
允许您调整有效位数!
如果要使用除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
0.075
到0.08
。它返回0.07
。
round
。docs.python.org/2/tutorial/floatingpoint.html#tut-fp-issues
f'{float(f"{i:.1g}"):g}'
# Or with Python <3.6,
'{:g}'.format(float('{:.1g}'.format(i)))
该解决方案与所有其他解决方案不同,因为:
对于任意数量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
)。如果需要这样做,则需要非标准功能,例如精确度软件包中提供的功能。
:g
保留整数的格式化程序的双重用途。
2000.0
显示 5个显著数字,所以它必须要经过{:g}
一次。)一般来说,尾随零整数是含糊地对待显著的数字,除非是一些技术(如划线高于去年显著)被使用。
我已经创建了可以满足您需求的高精度软件包。它使您可以为数字赋予或多或少的有效数字。
它还输出带有指定数量有效数字的标准,科学和工程符号。
在接受的答案中有一行
>>> 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'
lambda x: to_precision(x, 2)
将整数四舍五入到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)
为了直接回答这个问题,这是我使用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 docs和C standard是两个有用的参考。
为了说明这些数字是如何工作的,我们可以通过以下操作回到起点:
0x13333333333333 / 16**13 * 2**-4
应该打印出来0.075
。 16**13
是因为小数点后有13个十六进制数字,并且2**-4
是因为十六进制指数是以2为底的。
现在我们有了关于浮点数表示方式的一些想法,可以使用decimal
模块为我们提供更多的精度,向我们展示发生了什么事情:
from decimal import Decimal
Decimal(0x13333333333333) / 16**13 / 2**4
给:0.07499999999999999722444243844
并希望解释为什么round(0.075, 2)
评估0.07
0.074999999999999999
,你会想到在这种情况下获得?
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
我修改了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)
x == 0
呢?如果您喜欢单线飞机,那就return 0 if x==0 else round(...)
。
0.970 == 0.97
)。我认为您可以使用其他一些打印解决方案,例如f'{round_sig(0.9701, sig=3):0.3f}'
是否要打印零。
如果您想不涉及字符串而四舍五入,我发现上面的链接中隐藏了该链接:
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
如果您出于某些原因正在使用极小的值,则不会引发错误。
我想不出任何能够立即解决的问题。但是对于浮点数来说,它处理得很好。
>>> 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)
给出的答案是给出的最好的答案,但是它有很多限制,并且在技术上没有正确的有效数字。
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.
print(*[''.join([np.format_float_positional(.01*a*n,precision=2,unique=False,fractional=False,trim='k',pad_right=5) for a in [.99, .999, 1.001]]) for n in [8,9,10,11,12,19,20,21]],sep='\n')
。我没有检查Dragon4本身。
我也遇到了这个问题,但是我需要控制舍入类型。因此,我编写了一个快速函数(请参见下面的代码),该函数可以将值,舍入类型和所需的有效数字考虑在内。
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))
使用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+中,您可以省略前导0
s。
如果数字大于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)
希望能帮助到你。
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
给定一个如此彻底回答的问题,为什么不添加另一个
尽管上面的许多内容是可比的,但这更适合我的审美观
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)
不幸的是,最后一步不适用于数字数组-亲爱的读者,我会把这个留给您看看是否需要。
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