格式化浮点数而不尾随零


180

如何格式化浮点数,使其不包含尾随零?换句话说,我希望结果字符串尽可能短。

例如:

3 -> "3"
3. -> "3"
3.0 -> "3"
3.1 -> "3.1"
3.14 -> "3.14"
3.140 -> "3.14"

这个例子根本没有任何意义。 3.14 == 3.140-它们是相同的浮点数。因此,3.140000是相同的浮点数。零首先不存在。
S.Lott

33
@ S.Lott-我认为问题是在打印浮点数而没有尾随零,而不是两个数的实际等价。
博克斯塔德2010年

1
@pokstad:在这种情况下,没有“多余的”零。 %0.2f并且%0.3f是生产左边的最后数所需的两种格式。使用%0.2f产生右侧的最后两个数字。
S.Lott

6
3.0 -> "3"仍然是有效的用例。print( '{:,g}'.format( X )为我工作,以输出3X = 6 / 2何时何地X = 5 / 2获得2.5预期的输出。
ShoeMaker '16

1
旧的问题,但是.. print("%s"%3.140)给您您想要的。(我在下方添加了答案...)
drevicko

Answers:


177

我,我会做的('%f' % x).rstrip('0').rstrip('.')-保证定点格式,而不是科学记数法,等等等等呀,还不如光滑和优雅的%g,但是,它的工作原理(我不知道如何强制%g从不使用科学记数法; -)。


6
唯一的问题是最终'%.2f' % -0.0001会留下您。-0.00-0
科斯2012年

3
@ alexanderlukanin13,因为默认精度为6,请参阅docs.python.org/2/library/string.html'f' Fixed point. Displays the number as a fixed-point number. The default precision is 6.在上述解决方案中必须使用'%0.7f'。
derenio

3
@derenio好点:-)我只能补充一点,提高精度'%0.15f'是一个坏主意,因为奇怪的事情开始发生。
alexanderlukanin15 2013年

1
如果您位于其他字符串的中间: print('In the middle {} and something else'.format('{:f}'.format(a).rstrip('0')))
容错

1
@Alex Martelli,摆脱双重rstrip命令。只需简单地使用此方法即可.在一次操作中随后去除点()和所有尾随零:('%f' % x).rstrip('.0')
Gabriel Staples

143

您可以%g用来实现以下目的:

'%g'%(3.140)

或者,对于Python 2.6或更高版本:

'{0:g}'.format(3.140)

文档中查找formatg原因(除其他外)

从有效数中删除不重要的尾随零,并且如果在其后没有剩余数字,则也删除小数点。


28
哦,差不多了!有时,它会以科学计数法(“ 2.342E + 09”)格式化浮点数-是否可以将其关闭,即始终显示所有有效数字?
TarGz 2010年

5
为什么'{0:...}'.format(value)在可以使用时使用format(value, '...')?这避免了必须从否则为空的模板字符串中解析出格式说明符。
马丁·皮特斯

2
@MartijnPieters:解析格式说明符的微不足道的成本被其他开销的AFAICT所淹没;实际上,我在3.6上的本地基准测试(具有微基准测试的功能范围,可以准确地对真实代码进行建模)format(v, '2.5f')比大约要长10%'{:2.5f}'.format(v)。即使没有,我也倾向于使用str方法形式,因为当我需要对其进行调整,向其添加其他值等时,更改的内容很少。当然,从3.6版本开始,我们可以将f字符串用于大多数用途。:-)
ShadowRanger

5
在Python 3.6,这可以缩短到f"{var:g}"哪里var是浮点变量。
TheGreatCabbage

12

尝试最简单且可能最有效的方法呢?方法normalize()删除所有最右边的尾随零。

from decimal import Decimal

print (Decimal('0.001000').normalize())
# Result: 0.001

适用于Python 2Python 3

- 更新 -

@ BobStein-VisiBone指出的唯一问题是,数字10、100、1000 ...将以指数形式显示。可以使用以下函数轻松解决此问题:

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()

2
除了Decimal('10.0').normalize()变成'1E+1'
鲍勃·斯坦

11

在查看了几个类似问题的答案之后,这似乎是我的最佳解决方案:

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,但是会慢一些(〜30%)。

我本可以使用Decimal(inputValue).normalize(),但这也有一些问题。例如,速度要慢很多(〜11x)。我还发现,尽管它具有很高的精度,但使用时仍然会遭受精度损失normalize()

>>> Decimal('0.21000000000000000000000000006').normalize()
Decimal('0.2100000000000000000000000001')
>>> Decimal('0.21000000000000000000000000006')
Decimal('0.21000000000000000000000000006')

最重要的是,我仍然会转换为Decimal从,float这样您最终可以得到的不是您输入的数字。我认为Decimal当算术停留在DecimalDecimal使用字符串初始化时效果最佳。

>>> Decimal(1.35)
Decimal('1.350000000000000088817841970012523233890533447265625')
>>> Decimal('1.35')
Decimal('1.35')

我确信Decimal.normalize()可以使用上下文设置将的精度问题调整为所需的值,但是考虑到速度已经很慢并且不需要可笑的精度,而且无论如何我仍然会从浮点数转换而失去精度,我没有认为这不值得追求。

我不担心可能的“ -0”结果,因为-0.0是有效的浮点数,并且无论如何它都可能很少出现,但是由于您确实提到要保持字符串结果尽可能短,因此总是可以以很少的额外速度成本使用额外的条件。

def floatToString(inputValue):
    result = ('%.15f' % inputValue).rstrip('0').rstrip('.')
    return '0' if result == '-0' else result

1
不幸的是,仅适用于小数点左边少于五位或更多位数的数字。例如floatToString(12345.6)返回'12345.600000000000364'%.15f在此示例中,将15减小为一个较小的数字可以解决该问题,但是随着数字的增加,该值需要越来越小。可以基于该数字的log-base-10动态地计算它,但是很快变得非常复杂。
JohnSpeeks

1
解决该问题的一种方法可能是限制整数的长度(而不是限制小数点后的数字):result = ('%15f' % val).rstrip('0').rstrip('.').lstrip(' ')
蒂莫西·史密斯

@JohnSpeeks我不确定这是可以避免的。如果左侧需要更多位数,则浮点数将无法表示精度,这是一个副作用。据我所知,以字符串形式出现的数字与以浮点数输入的数字相同,或者至少是其最接近的表示形式。>>>12345.600000000000364 == 12345.6 True
PolyMesh

我写了另一个解决方案
niitsuma

8

这是一个对我有用的解决方案。这是一个混合的解决方案通过多网并使用新的.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

唯一有问题的是,您必须设置一个合理的十进制数字。设置得越高,您可以代表的数字越精确,但是如果您这样做太多,则会降低性能。
beruic

1
加上beruic的评论,此方法不适用于精度更高的浮点数(例如3.141),因为它们.2f是硬编码的。
TrebledJ

3

您可以简单地使用format()实现此目的:

format(3.140, '.10g') 其中10是您想要的精度。


2
>>> str(a if a % 1 else int(a))

不是int(a) if a % 1 else a
beruic

亲爱的贝鲁克,您的答案是否定的。a if a % 1 else int(a)是正确的。问题需要以字符串形式输出,所以我刚刚添加了str
Shameem

啊,我明白了。a % 1是真实的,因为它不为零。我隐含和错误地认为它是a % 1 == 0
比利时

2

尽管格式化可能是大多数Python方式,但这里是使用该more_itertools.rstrip工具的替代解决方案。

import more_itertools as mit


def fmt(num, pred=None):
    iterable = str(num)
    predicate = pred if pred is not None else lambda x: x in {".", "0"}
    return "".join(mit.rstrip(iterable, predicate))

assert fmt(3) == "3"
assert fmt(3.) == "3"
assert fmt(3.0) == "3"
assert fmt(3.1) == "3.1"
assert fmt(3.14) == "3.14"
assert fmt(3.140) == "3.14"
assert fmt(3.14000) == "3.14"
assert fmt("3,0", pred=lambda x: x in set(",0")) == "3"

该数字将转换为字符串,该字符串将除去满足谓词的结尾字符。函数定义fmt不是必需的,但是在这里用于测试所有通过的断言。注意:它适用于字符串输入并接受可选谓词。

另请参阅有关此第三方库的详细信息more_itertools


1

如果您可以将3.和3.0都显示为“ 3.0”,那么这是一种非常简单的方法,可将浮点数表示形式的零右移:

print("%s"%3.140)

(感谢@ellimilial指出例外)


1
但是print("%s"%3.0)可以。
ellimilial '18

1

您可以选择使用QuantiPhy软件包。通常,在处理带有单位和SI比例因子的数字时,会使用QuantiPhy,但它具有多种不错的数字格式设置选项。

    >>> from quantiphy import Quantity

    >>> cases = '3 3. 3.0 3.1 3.14 3.140 3.14000'.split()
    >>> for case in cases:
    ...    q = Quantity(case)
    ...    print(f'{case:>7} -> {q:p}')
          3 -> 3
         3. -> 3
        3.0 -> 3
        3.1 -> 3.1
       3.14 -> 3.14
      3.140 -> 3.14
    3.14000 -> 3.14

在这种情况下,它将不使用电子符号:

    >>> cases = '3.14e-9 3.14 3.14e9'.split()
    >>> for case in cases:
    ...    q = Quantity(case)
    ...    print(f'{case:>7} -> {q:,p}')
    3.14e-9 -> 0
       3.14 -> 3.14
     3.14e9 -> 3,140,000,000

您可能更喜欢的替代方法是使用SI比例因子,也许使用单位。

    >>> cases = '3e-9 3.14e-9 3 3.14 3e9 3.14e9'.split()
    >>> for case in cases:
    ...    q = Quantity(case, 'm')
    ...    print(f'{case:>7} -> {q}')
       3e-9 -> 3 nm
    3.14e-9 -> 3.14 nm
          3 -> 3 m
       3.14 -> 3.14 m
        3e9 -> 3 Gm
     3.14e9 -> 3.14 Gm

0

OP希望删除多余的零,并使生成的字符串尽可能短。

我发现%g指数格式会缩短结果字符串的大小和数值。对于不需要指数表示法的值(例如128.0)来说,问题来了,它既不是很大也不是很小。

这是将数字格式化为短字符串的一种方法,仅当Decimal.normalize创建的字符串过长时才使用%g指数表示法。这可能不是最快的解决方案(因为它确实使用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']



0

答案是:

import numpy

num1 = 3.1400
num2 = 3.000
numpy.format_float_positional(num1, 3, trim='-')
numpy.format_float_positional(num2, 3, trim='-')

输出“ 3.14”和“ 3”

trim='-' 删除尾随零和小数。


-1

使用宽度足够大的%g,例如'%.99g'。对于任何较大的数字,它将以定点表示法打印。

编辑:这不起作用

>>> '%.99g' % 0.0000001
'9.99999999999999954748111825886258685613938723690807819366455078125e-08'

1
.99是精度,不是宽度;有点用,但是您无法通过这种方式设置实际精度(除了自己截断之外)。
科斯2012年

-1

您可以这样使用max()

print(max(int(x), x))


1
您必须考虑x负数的情况。 if x < 0: print(min(x), x) else : print(max(x), x)
watou

当我想进行json字符串化时的一种有用方法。将float 1.0更改为int 1,因此其性能与javascript中的相同。
pingze

-3

您可以通过以下大多数pythonic方式实现该目标:

python3:

"{:0.0f}".format(num)

你是对的。最简单的方法是使用“ {:g}”。format(num)
Pyglouthon

-4

处理%f,您应该放

%.2f

,其中:.2f == .00浮动。

例:

打印“价格:%.2f”%价格[产品]

输出:

价格:1.50


1
明确指出这不是问题要的。需要下注。
yang19年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.