格式化浮点数去除尾随零

294 投票
19 回答
208802 浏览
提问于 2025-04-15 20:24

我想知道怎么把一个浮点数格式化成没有多余零的样子。换句话说,我希望得到的字符串尽可能简短。

比如:

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

19 个回答

29

看了几个类似问题的回答后,我觉得这个方案对我来说是最好的:

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
275

你可以用 %g 来实现这个效果:

'%g'%(3.140)

或者,如果你使用的是 Python 版本大于等于 2.6:

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

或者,如果你使用的是 Python 版本大于等于 3.6:

f'{3.140:g}'

根据 format 的文档g 的作用是:

会把不重要的尾随零去掉,同时如果小数点后面没有数字,小数点也会被去掉。

246

我会用 ('%f' % x).rstrip('0').rstrip('.') 这个方法。这样可以确保输出是固定小数点格式,而不是科学计数法等等。虽然这个方法没有 %g 那么简洁优雅,但它确实有效(而且我不知道怎么让 %g 永远不使用科学计数法;-)。

撰写回答