如何格式化浮点数以使其不包含尾随零?换句话说,我希望生成的字符串尽可能短。
例如:
3 -> "3"
3. -> "3"
3.0 -> "3"
3.1 -> "3.1"
3.14 -> "3.14"
3.140 -> "3.14"
如何格式化浮点数以使其不包含尾随零?换句话说,我希望生成的字符串尽可能短。
例如:
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)
或者,使用 Python ≥ 3.6:
f'{3.140:g}'
来自文档format
:g
原因(除其他外)
从有效数字中删除无关紧要的尾随零,如果后面没有剩余数字,小数点也会被删除。
在查看了几个类似问题的答案后,这对我来说似乎是最好的解决方案:
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
from ,float
这会使您最终得到的不是您输入的数字。我认为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
尝试最简单且可能最有效的方法怎么样?方法normalize()删除所有最右边的尾随零。
from decimal import Decimal
print (Decimal('0.001000').normalize())
# Result: 0.001
适用于Python 2和Python 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()
您可以简单地使用 format() 来实现这一点:
format(3.140, '.10g')
其中 10 是您想要的精度。
more_itertools.rstrip
虽然格式化可能是大多数 Pythonic 方式,但这里有一个使用该工具的替代解决方案。
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
.
如果你想要一些适用于数字或字符串输入的东西:
def num(s):
""" 3.0 -> 3, 3.001000 -> 3.001 otherwise return s """
s = str(s)
try:
int(float(s))
return s.rstrip('0').rstrip('.')
except ValueError:
return s
>>> for n in [3, 3., 3.0, 3.1, 3.14, 3.140, 3.001000 ]: print(num(n))
...
3
3
3
3.1
3.14
3.14
3.001
>>> for n in [3, 3., 3.0, 3.1, 3.14, 3.140, 3.001000 ]: print(num(str(n)))
...
3
3
3
3.1
3.14
3.14
3.001
>>> str(a if a % 1 else int(a))
这是答案:
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='-'
删除尾随零和小数。
使用 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
试试这个,它可以让你添加一个“精度”变量来设置你想要的小数位数。请记住,它会四舍五入。请注意,这仅在字符串中有小数时才有效。
number = 4.364004650000000
precision = 2
result = "{:.{}f}".format(float(format(number).rstrip('0').rstrip('.')), precision)
输出
4.364004650000000
4.36
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']
如果您可以忍受 3. 和 3.0 显示为“3.0”,这是一种非常简单的方法,可以从浮点表示中右剥离零:
print("%s"%3.140)
(感谢@ellimilial 指出例外情况)
对于浮动,你可以使用这个:
def format_float(num):
return ('%i' if num == int(num) else '%s') % num
测试它:
>>> format_float(1.00000)
'1'
>>> format_float(1.1234567890000000000)
'1.123456789'
对于十进制,请参见此处的解决方案:https ://stackoverflow.com/a/42668598/5917543
使用宽度足够大的 %g,例如 '%.99g'。对于任何相当大的数字,它将以定点表示法打印。
编辑:它不起作用
>>> '%.99g' % 0.0000001
'9.99999999999999954748111825886258685613938723690807819366455078125e-08'
"{:.5g}".format(x)
我用它来格式化浮点数以跟踪零。
你可以max()
这样使用:
print(max(int(x), x))
您可以像这样以大多数pythonic方式实现这一点:
蟒蛇3:
"{:0.0f}".format(num)
处理 %f 你应该把
%.2f
,其中: .2f == .00 浮动。
例子:
打印“价格:%.2f”%价格[产品]
价格:1.50