Python浮点数精度格式说明符

9

假设我有一些32位数字和一些64位数字:

>>> import numpy as np
>>> w = np.float32(2.4)
>>> x = np.float32(4.555555555555555)
>>> y = np.float64(2.4)
>>> z = np.float64(4.555555555555555)

我可以使用%f将它们打印出来,但是会有额外的、不必要的小数位:

>>> '%f %f %f %f' % (w, x, y, z)
'2.400000 4.555555 2.400000 4.555556'

我可以使用%g,但它似乎有一个小的默认精度:

>>> '%g %g %g %g' % (w, x, y, z)
'2.4 4.55556 2.4 4.55556'

我在考虑,对于32位的值可以使用.7,而对于64位的值则可以使用.15

>>> '%.7g %.7g %.15g %.15g' % (w, x, y, z)
'2.4 4.555555 2.4 4.55555555555556'

这种方法似乎相当有效,但精度数字也用于小数点前面的数字,例如34567.375768。

总之,序列化浮点值以便将适当的精度保留为32位和64位值的正确方法是什么,但又不会使用任何不必要的空间?

更新:

我认为输出应该是什么样子的例子:

number                float32     float64
5                     5           5
0.1                   0.1         0.1
2.4                   2.4         2.4
4.555555555555555     4.5555553   4.5555555555555554
12345678.92345678635  12345679.0  12345678.923456786

.7/.16的含义是什么?实际上看起来还不错:

>>> v32 = np.array([5, 0.1, 2.4, 4.555555555555555, 12345678.92345678635], dtype=np.float32)
>>> v64 = np.array([5, 0.1, 2.4, 4.555555555555555, 12345678.92345678635], dtype=np.float64)
>>> ('%.7g ' * len(v32)) % tuple(v32)
'5 0.1 2.4 4.555555 1.234568e+07 '
>>> ('%.16g ' * len(v64)) % tuple(v64)
'5 0.1 2.4 4.555555555555555 12345678.92345679 '

我会简单地使用 strip('0') 来去除尾部的零。 - Hans Then
"%.3f" % z -> '4.556', "%.3f" % q -> '2131234.556' 这段代码有什么问题? - Dr. Jan-Philip Gehrcke
2
“%.16g”(我认为.16是正确的)不完全符合您的需求吗?始终具有16个有效数字...您也可以使用“%r”(表示),这可能会得到相同的结果。“用完前面”的听起来像您对浮点数有一些误解? - seberg
精度数字也被用于小数点前的数字,这是一个特性。由于这些数字也占据空间,它们与小数点后的数字一样重要。当我们谈论“显著”的15或7个数字时,数字总数始终指的是所有数字的数量。 - user4815162342
@seberg 我觉得我可能误解了浮点值的正确表示方式。那么 .7/.16 是正确的吗? - jterrace
显示剩余2条评论
2个回答

8
你可以尝试使用 np.finfo 函数来获取与你的浮点数对应的精度。
finfo32 = np.finfo(np.float32)
finfo64 = np.finfo(np.float64)

finfo32.resolution = 1e-6
finfo64.resolution = 1e-15

现在你知道你需要保留几位小数,比如说6位,只需使用 rstrip("0") 去掉不必要的0:

print ("%.6f" % your_float).strip("0")

如果你倾向于使用%g,也许你想使用动态格式,例如:

>>> strf = lambda v: ("%%.%ig" % max(np.ceil(np.log10(v)), 7)) % v
>>> strf(123.456789)
'123.45679'
>>> strf(123456789.12345)
'123456789'

更新的问题,我认为 %g 实际上做我想要的事情。 - jterrace
@jterrace:我不确定,用'%.7g'检查v32的最后一个条目。 - Pierre GM
看起来很奇怪,它是“1.234568e+07”而不是“1.234569e+07”? - jterrace
这就是%g的作用..如果更有效率,它会使用%e。我其实可以接受科学计数法。 - jterrace
是的,这个例子是我认为答案应该是什么,但我想 %g 也可以。我仍然不确定我应该使用什么精度来确保不失去精度。 - jterrace

2
我不是很确定你想要实现什么。不过这可能会有所帮助。你写道:
“这似乎运行得相当好,但精度数字也用于小数点前面的数字,例如34567.375768。”
你可以使用%f而不是g。来自Python{{link1:docs}}:
引用: “精度是一个十进制数字,表示应在格式化为'f'和'F'的浮点值后显示多少位小数点,或者在格式化为'g'或'G'的浮点值之前和之后显示多少位小数点。”
>>> z = np.float64(4.555555555555555)
>>> "%.3f" % z
'4.556'
>>> q = np.float64(2131234.555555555555555)
>>> "%.3f" % q
'2131234.556'
>>>

然后将“3”更改为另一个值。我仍然不完全明白你想要什么。 - Dr. Jan-Philip Gehrcke

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接