格式化是浮动的,没有后面的零

我如何格式化一个浮点数,使它不包含尾随零?换句话说,我希望得到的字符串尽可能短。

例如:

3 -> "3"
3. -> "3"
3.0 -> "3"
3.1 -> "3.1"
3.14 -> "3.14"
3.140 -> "3.14"
177868 次浏览

你可以使用%g来实现:

'%g'%(3.140)

或者,Python≥2.6:

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

或者,Python≥3.6:

f'{3.140:g}'

来自format的docs: g原因(除其他外)

后面不重要的零 从意义上移除,和 如果有,小数点也会被移除

我,我会用('%f' % x).rstrip('0').rstrip('.')——保证定点格式,而不是科学符号,等等。是的,不像%g那么流畅和优雅,但是,它是有效的(而且我不知道如何强迫%g永远不使用科学符号;-)。

使用宽度足够大的%g,例如'%.99g'。 它将以定点表示法输出任何相当大的数字

编辑:它不起作用

>>> '%.99g' % 0.0000001
'9.99999999999999954748111825886258685613938723690807819366455078125e-08'
试试最简单、可能也是最有效的方法怎么样? normalize ()方法删除所有最右边的尾随0
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()

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

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(),但这也有一些问题。首先,它慢了很多(~11倍)。我还发现,尽管它具有相当高的精度,但在使用normalize()时,它仍然会遭受精度损失。

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

最重要的是,我仍然会从float转换到Decimal,这可能会使你最终得到其他东西,而不是你在那里输入的数字。我认为当算术留在Decimal中并且Decimal用字符串初始化时,Decimal工作得最好。

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

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

我发现%g指数格式缩短了非常大和非常小的值的结果字符串。问题出现在不需要指数符号的值上,比如128.0,它既不是很大也不是很小。

这里有一种将数字格式化为短字符串的方法,仅在Decimal时使用%g指数表示法。Normalize创建的字符串太长。这可能不是最快的解决方案(因为它使用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是你想要的精度。

对于float,你可以使用这个:

def format_float(num):
return ('%i' if num == int(num) else '%s') % num

测试:

>>> format_float(1.00000)
'1'
>>> format_float(1.1234567890000000000)
'1.123456789'

Decimal参见这里的解:https://stackoverflow.com/a/42668598/5917543

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

这里有一个对我有用的解决办法。它混合了解决方案PolyMesh,并使用了新的.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

虽然格式化可能是最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的详细信息。

你可以用最python的方式来实现:

python3:

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

如果你能接受3个。3.0以“3.0”的形式出现,这是一种非常简单的方法,从浮点数表示中右移零:

print("%s"%3.140)

(感谢@ellimilial指出了例外情况)

你可以像这样使用max():

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

处理%f和你应该放

% .2f

< p >,地点: .2f == .00 floats.

.0

例子:

价格:%。2f" %价格[产品]

输出:

价格:1.50

使用QuantiPhy包是一个选项。通常QuantiPhy用于 使用数字单位和SI比例因子,但它有各种

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

在这种情况下,它不会使用e符号:

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

"{:.5g}".format(x)

我用这个来格式化浮点到尾零。

以下是答案:

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='-'删除后面的0和小数点。

试试这个,它将允许您添加一个“精确”;变量设置您想要的小数点后多少位。只要记住它会四舍五入。请注意,这只适用于字符串中有小数的情况。

 number = 4.364004650000000
precision = 2
result = "{:.{}f}".format(float(format(number).rstrip('0').rstrip('.')), precision)

输出

 4.364004650000000
4.36

如果你想要一些既适用于数字输入又适用于字符串输入的东西(感谢@mike-placentra的bug搜索):

def num(s):
""" 3.0 -> 3, 3.001000 -> 3.001 otherwise return s """
s = str(s)
try:
int(float(s))
if '.' not in s:
s += '.0'
return s.rstrip('0').rstrip('.')
except ValueError:
return s


>>> for n in [3, 3., 3.0, 3.1, 3.14, 3.140, 3.001000, 30 ]: print(num(n))
...
3
3
3
3.1
3.14
3.14
3.001
30


>>> for n in [3, 3., 3.0, 3.1, 3.14, 3.140, 3.001000, 30 ]: print(num(str(n)))
...
3
3
3
3.1
3.14
3.14
3.001
30

一个新的挑战者出现了。

def prettify_float(real: float, precision: int = 2) -> str:
'''
Prettify the passed floating-point number into a human-readable string,
rounded and truncated to the passed number of decimal places.


This converter prettifies floating-point numbers for human consumption,
producing more readable results than the default :meth:`float.__str__`
dunder method. Notably, this converter:


* Strips all ignorable trailing zeroes and decimal points from this number
(e.g., ``3`` rather than either ``3.`` or ``3.0``).
* Rounds to the passed precision for perceptual uniformity.


Parameters
----------
real : float
Arbitrary floating-point number to be prettified.
precision : int, optional
**Precision** (i.e., number of decimal places to round to). Defaults to
a precision of 2 decimal places.


Returns
----------
str
Human-readable string prettified from this floating-point number.


Raises
----------
ValueError
If this precision is negative.
'''


# If this precision is negative, raise an exception.
if precision < 0:
raise ValueError(f'Negative precision {precision} unsupported.')
# Else, this precision is non-negative.


# String prettified from this floating-point number. In order:
# * Coerce this number into a string rounded to this precision.
# * Truncate all trailing zeroes from this string.
# * Truncate any trailing decimal place if any from this string.
result = f'{real:.{precision}f}'.rstrip('0').rstrip('.')


# If rounding this string from a small negative number (e.g., "-0.001")
# yielded the anomalous result of "-0", return "0" instead; else, return
# this result as is.
return '0' if result == '-0' else result

不要相信我的谎言

__abc0风格的单元测试或它没有发生。

def test_prettify_float() -> None:
'''
Test usage of the :func:`prettify_float` prettifier.
'''


# Defer test-specific imports.
from pytest import raises


# Assert this function prettifies zero as expected.
assert prettify_float(0.0) == '0'


# Assert this function prettifies a negative integer as expected.
assert prettify_float(-2.0) == '-2'


# Assert this prettifier prettifies a small negative float as expected.
assert prettify_float(-0.001) == '0'


# Assert this prettifier prettifies a larger negative float as expected.
assert prettify_float(-2.718281828) == '-2.72'
assert prettify_float(-2.718281828, precision=4) == '-2.7183'


# Assert this function prettifies a positive integer as expected.
assert prettify_float(3.0) == '3'


# Assert this function prettifies a positive float as expected.
assert prettify_float(3.14159265359) == '3.14'
assert prettify_float(3.14159265359, precision=4) == '3.1416'


# Assert this prettifier raises the expected exception when passed a
# negative precision.
with raises(ValueError):
prettify_float(2.718281828, precision=-2)

%100纯Python

忽略那些诱人的简单答案,比如:

  • 它们都在常见的边缘情况下失败,比如整数或小的负浮点数。
  • 第三方包。 NumPy, QuantiPhy和more_itertools?你肯定是在开玩笑。不要额外增加维护负担或代码债务。也就是说……

< >强@beartype < / >强扔给prettify_float()以增加运行时安全性,你就成功了!你的用户群会对你赞不绝口。所以我也会。而且,我很确定我的偏见显示在这里

另请参阅

这个答案站在巨大的猛犸象的肩膀上,包括:

  1. 马特利亚历克斯 聪明的接受答案
  2. PolyMesh 推广Martelli的答案,以捕捉小负浮点数的边缘情况
  3. Kaushal莫迪 泛化PolyMesh的答案,迫使精度为小数点后两位