为了方便一目了然的比较,我的项目中的统计结果通常最好采用
0.3f
的格式,除了(a)小数位无用,或(b)有一个小分数,前三位都是零。从 Python 3.11.8 开始,似乎没有一种内置格式可以始终给出数量级,同时最大限度地减少无用数字。对标准格式的每个字符使用循环,可以调整结果以满足这些要求,但似乎效率低下且不必要的详细:
class FloatFormatter:
def within(n, minimum, maximum):
s = '{:.{m}f}'.format(n, m=maximum)
decimal = truncate = False
i = 0
for c in s:
i += 1
match c:
case '0':
continue
case '.':
dot = i
decimal = True
case _:
if (decimal):
truncate = True
break
if decimal:
places = (i - dot)
if places < minimum:
return s[:dot+minimum].rstrip('0') # minimum precision modulo trailing zeros
if truncate:
return s[:i].rstrip('0') # precision up to first non-zero
if n > 1.0:
return str(int(n)) + '.0_'
else:
return '* ' + '{:.0e}'.format(n)[1:] # sci-fi format with only the order of magnitude
else:
return s.rstrip('0').rstrip('.') # just the integer
用途:
>>> x = 1.23456
>>> print("• x: " + FloatFormatter.within(x, 3, 10))
• x: 1.234
特殊情况 1:显示额外的小数位(最多 10 位)以保留数量级
>>> x = 1.000023456
>>> print("• x: " + FloatFormatter.within(x, 3, 10))
• x: 1.00002
特殊情况 2:精度 10 不足以达到非零,所以只需表明它略高于零
>>> x = 1.00000000000023456
>>> print("• x: " + FloatFormatter.within(x, 3, 10))
• x: 1.0_
特殊情况3:保留数量级而不提供更多细节
>>> x = 0.00000000000023456
>>> print("• x: " + FloatFormatter.within(x, 3, 10))
• x: * e-13
是否有更简单的方法来实现相同的基本想法?
您是否正在寻找重要的数字格式?
nums = np.random.uniform(-1, 1, 10)**6
for n in nums:
print(f'{n:.3g}')
0.531
0.0515
0.000998
0.0097
0.235
0.000131
1.9e-06
1.62e-06
0.0133
3.99e-05
您可以使用您开始使用的类为浮点数构建自定义格式化程序。 不要每次都传入最小和最大小数位,而是设置一次,然后让对象引用这些值。
您还可以重写
__add__
和 __radd__
方法来简化对象的使用,将其添加到浮点数会返回格式化字符串。
class FloatFormatter:
def __init__(self, min_sigfig: int=3, max_sigfig: int=10):
self.min_sigfig = min_sigfig
self.max_sigfig = max_sigfig
def format(self, x: float) -> str:
i = int(x)
d = (x - i) if i >= 0 else -(x - i)
dstr = str(d).replace('.','').lstrip('0')
n = -math.log10(d) if d>0.0 else 0.1
# handle exact power of 10
if n.is_integer():
n -= 1.0
n = int(n)
if n <= self.min_sigfig:
suffix = '0'*n + dstr[:self.min_sigfig-n]
elif n <= self.max_sigfig:
suffix = '0'*n + dstr[0]
else:
suffix = '_'
return f'{i}.{suffix}'
def __add__(self, other: float):
return self.format(other)
def __radd__(self, other: float):
return self.format(other)
ff = FloatFormatter()
要使用格式化程序,只需将其添加到浮动中即可:
>>> 1.012345 + ff
'1.012'
>>> 1.34567 + ff
'1.345'
>>> 1.00897 + ff
'1.008'
>>> 1.000000222 + ff
'1.0000002`
>>> 1.00000000000643 + ff
'1._'
>>> 1.0000000000000000000000000888 + ff # this is beyond the precision limit
'1.'