我需要对浮点数进行舍入以在UI中显示。例如,一个重要数字:
1234 -> 1000
0.12 -> 0.1
0.012 -> 0.01
0.062 -> 0.06
6253 -> 6000
1999 -> 2000
有没有一种很好的方法可以使用Python库来实现这一点,还是我必须自己编写?
您可以使用负数来舍入整数:
>>> 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转换为整数。
如果你想在不涉及字符串的情况下进行舍入,我发现的链接隐藏在上面的注释中:
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)) ) )
它适用于任何标量数值,如果您因某种原因需要移动响应,则n可以是float
。您实际上可以将限制推送到:
sys.float_info.min*sys.float_info.epsilon
不引发错误,如果由于某种原因你正在使用微小的值。
我也碰到了这个,但我需要控制舍入类型。因此,我编写了一个快速函数(参见下面的代码),它可以将值,舍入类型和所需的有效数字考虑在内。
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+ new-style formatting(不推荐使用%-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
这将返回一个字符串,因此没有小数部分的结果,以及以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))
字符串格式化中的%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'
如果你想得到除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
print('{:g}'.format(float('{:.1g}'.format(12.345))))
此解决方案与所有其他解决方案不同,因为:
对于任意数字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
)的数字。如果您需要这样做,那么需要非标准函数,如to-precision包中提供的函数。
要将整数舍入为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-precision包,可以满足您的需求。它允许您给出数字或多或少的重要数字。
它还输出具有指定数量的有效数字的标准,科学和工程符号。
在接受的答案中有一条线
>>> 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'
我修改了indgar的解决方案来处理负数和小数(包括零)。
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)
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
我想不出任何能够开箱即用的东西。但它对浮点数的处理相当好。
>>> 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)