用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 2Python 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.formatfunction。 如果你只是用str(例如str(.0300) – > 0.3 )进行转换,那么大多数情况下,它就是所需要的。 如果这个数字足够小或者足够大,它将使用指数表示法,但是大多数情况下只会打印一个没有拖尾(或前导)零的浮点数。 如果格式string是空的,那么它实质上是str()的输出,所以这应该工作,如果这是所需的function:

 '{0}'.format(fp_num) 

即使这是唯一被格式化的东西,

 '{}'.format(fp_num) 

有可能使用formatfunction:

 {}.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详细信息。