用Python格式化浮点数而不用多余的零
如何格式化一个浮点数,使其不包含剩余的零点? 换句话说,我希望得到的string越短越好。
喜欢:
3 -> "3" 3. -> "3" 3.0 -> "3" 3.1 -> "3.1" 3.14 -> "3.14" 3.140 -> "3.14"
我,我会做('%f' % x).rstrip('0').rstrip('.')
– 保证定点格式而不是科学记数法等等等等。作为%g
,但是,它的工作(我不知道如何迫使%g
不要使用科学记数法;-)。
你可以使用%g
来达到这个目的:
'%g'%(3.140)
或者,对于Python 2.6或更高版本:
'{0:g}'.format(3.140)
从format
的文档 : g
原因(除其他外)
不重要的尾随零将被从有效数字中去除,并且如果在其之后没有剩余的数字,则小数点也被去除。
尝试最简单,可能最有效的方法呢? normalize()方法删除所有最右边的尾部零。
from decimal import Decimal print (Decimal('0.001000').normalize()) # Result: 0.001
适用于Python 2和Python 3 。
– 更新 –
@ BobStein-VisiBone指出的唯一问题是像10,100,1000这样的数字将以指数forms显示。 这可以很容易地使用下面的函数来修复:
from decimal import Decimal def format_float(f): d = Decimal(str(f)); return d.quantize(Decimal(1)) if d == d.to_integral() else d.normalize()
看了几个类似问题的答案后,这似乎是对我来说最好的解决scheme:
def floatToString(inputValue): return ('%.15f' % inputValue).rstrip('0').rstrip('.')
我的推理:
%g
没有摆脱科学记数法。
>>> '%g' % 0.000035 '3.5e-05'
小数点后15位似乎可以避免奇怪的行为,并具有足够的精度来满足我的需求。
>>> ('%.15f' % 1.35).rstrip('0').rstrip('.') '1.35' >>> ('%.16f' % 1.35).rstrip('0').rstrip('.') '1.3500000000000001'
我可以使用format(inputValue, '.15f').
而不是'%.15f' % inputValue
,但是有点慢( '%.15f' % inputValue
%)。
我可以使用Decimal(inputValue).normalize()
,但是这也有一些问题。 首先,它是一个很慢(约11倍)。 我也发现,虽然它具有相当高的精度,但在使用normalize()
时仍然存在精度损失。
>>> Decimal('0.21000000000000000000000000006').normalize() Decimal('0.2100000000000000000000000001') >>> Decimal('0.21000000000000000000000000006') Decimal('0.21000000000000000000000000006')
最重要的是,我仍然会从一个float
转换为Decimal
,这会使你最终得到的数字不是你放在那里的数字。 我认为Decimal
在算术保持Decimal
效果最好, Decimal
用string初始化。
>>> Decimal(1.35) Decimal('1.350000000000000088817841970012523233890533447265625') >>> Decimal('1.35') Decimal('1.35')
我确定Decimal.normalize()
的精确度问题可以根据上下文设置进行调整,但是考虑到速度已经很慢了,不需要那么荒谬的精确度,而且我仍然会从一个浮点数转换无论如何,我不认为这值得追求。
我不关心可能的“-0”结果,因为-0.0是一个有效的浮点数,它可能是一个罕见的发生,但是既然你提到你想保持string结果尽可能短,你总是可以使用额外的条件,只需要很小的额外的速度成本。
def floatToString(inputValue): result = ('%.15f' % inputValue).rstrip('0').rstrip('.') return '0' if result == '-0' else result
这是一个为我工作的解决scheme。 它是PolyMesh 解决scheme的混合体,以及新的.format()
语法的使用 。
for num in 3, 3., 3.0, 3.1, 3.14, 3.140: print('{0:.2f}'.format(num).rstrip('0').rstrip('.'))
输出 :
3 3 3 3.1 3.14 3.14
>>> str(a if a % 1 else int(a))
使用宽度足够大的%g,例如'%.99g'。 它将以定点表示法打印任何合理的大数字。
编辑:它不工作
>>> '%.99g' % 0.0000001 '9.99999999999999954748111825886258685613938723690807819366455078125e-08'
我认为有一个更简单的方法来做到这一点与新的str.format
function。 如果你只是用str(例如str(.0300)
– > 0.3
)进行转换,那么大多数情况下,它就是所需要的。 如果这个数字足够小或者足够大,它将使用指数表示法,但是大多数情况下只会打印一个没有拖尾(或前导)零的浮点数。 如果格式string是空的,那么它实质上是str()
的输出,所以这应该工作,如果这是所需的function:
'{0}'.format(fp_num)
即使这是唯一被格式化的东西,
'{}'.format(fp_num)
有可能使用format
function:
{}.format(float)
OP想要删除超级浪费的零,并使得到的string尽可能短。
我发现%g指数格式缩小了非常大和非常小的值的结果string。 问题出现在不需要指数表示法的值,如128.0,既不是非常大也不是很小。
只有当Decimal.normalize创build的string过长时,才能将数字格式化为使用%g指数表示法的短string。 这可能不是最快的解决scheme(因为它使用Decimal.normalize)
def floatToString (inputValue, precision = 3): rc = str(Decimal(inputValue).normalize()) if 'E' in rc or len(rc) > 5: rc = '{0:.{1}g}'.format(inputValue, precision) return rc inputs = [128.0, 32768.0, 65536, 65536 * 2, 31.5, 1.000, 10.0] outputs = [floatToString(i) for i in inputs] print(outputs) # ['128', '32768', '65536', '1.31e+05', '31.5', '1', '10']
你可以简单地使用format()来实现这个:
format(3.140, '.10g')
,其中10是你想要的精度。
对于浮动,你可以使用这个:
def format_float(num): return ('%i' if num == int(num) else '%s') % num
testing它:
>>> format_float(1.00000) '1' >>> format_float(1.1234567890000000000) '1.123456789'
十进制请参阅解决scheme: https : //stackoverflow.com/a/42668598/5917543
虽然格式化可能是大多数Pythonic方式,但这是使用more_itertools.rstrip
工具的替代解决scheme。
def f(num): iterable = str(num) pred = lambda x: x in {".", "0", ".0"} return "".join(mit.rstrip(iterable, pred)) assert f(3) == "3" assert f(3.) == "3" assert f(3.0) == "3" assert f(3.1) == "3.1" assert f(3.14) == "3.14" assert f(3.140) == "3.14"
该数字被转换为一个string,剥离满足谓词的尾随字符。 函数定义f
并不是必需的,但是它在这里被用来testing所有的断言。
另请参阅有关此第三方库more_itertools
详细信息。