首页 > 解决方案 > 字符串格式不能正确处理四舍五入的 Numpy Float32?

问题描述

将格式字符串与 Numpy 32 float 和 Numpy.round() 一起使用时,我意外地遇到了这种奇怪的行为。重现:

score=0.7827188774

npf32_score_rounded=np.round(np.float32(0.7827188774),4)
score_rounded=np.round(score,4)

print(f" {npf32_score_rounded}")
print(f" {score_rounded}")

print(npf32_score_rounded)
print(score_rounded)

#0.7827000021934509 expect to get 0.7827
#0.7827
#0.7827 # without string format, it works as expected
#0.7827

这种行为是正常的还是应该修复?

Numpy 版本 == 1.20.2

Python 版本 == 3.8.0

标签: pythonnumpy

解决方案


Python 的 f 字符串调用 objects__format__函数。从numpy 的源代码中可以看出,对于浮点数,它float之前会转换为 Python(64 位)。


由于存储在 32 位浮点数中的值实际上是0.782700002193450927734375(参见IEE 754),因为 Python 的精度更高,float所以这些小数位现在很重要。这就是现在打印这些小数位的原因。感谢@user2357112 支持 Monica指出这一点。

所以这是预期的结果。


import numpy as np

val = 0.7827188774

np_float_32 = np.round(np.float32(val), 4)
assert type(np_float_32) == np.float32

np_float_64 = np.round(val, 4)
assert type(np_float_64) == np.float64

# just calling print, no issues
print(np_float_32, np_float_64) # 0.7827 0.7827

# both str and repr work as intended
print(str(np_float_32), str(np_float_64)) # 0.7827 0.7827
print(repr(np_float_32), repr(np_float_64)) # 0.7827 0.7827

# behavior described by OP
print(f'{np_float_32} {np_float_64}') # 0.7827000021934509 0.7827

# f-string without format specification calls obj.__format__('')
# see https://github.com/numpy/numpy/blob/v1.20.2/numpy/core/src/multiarray/scalartypes.c.src#L273
# explicit conversion to python float
print(float(np_float_32), float(np_float_64)) # 0.7827000021934509 0.7827

推荐阅读