我使用空间数据,并且经常拥有最多只需要精确到小数点后几位的坐标,例如
89.995
。
一个简单的例子:
import numpy as np
arr = np.array([89.995])
检查数据类型:
>>> y.dtype
dtype('float64')
>>> arr[0]
-89.995 # This is what I need. Good.
但就我的目的而言,我经常处理大型网格数据,不需要 64 位浮点数的精度,因此我想将坐标值向下转换为
float32
,或者理想情况下为 float16
以减少内存加载。然而,在向下转型之后,在检查项目时,我看到了 float64
中不存在的精度问题,尽管这些值远未超过 float32
的精度限制。
例如
>>> arr[0].item()
-89.995
>>> arr[0].astype(np.float32).item()
-89.99500274658203
我需要准确的坐标。由于我主要在
numpy
环境中工作,我应该关心这个吗?它们在功能上是否具有相同的值(我只是误解了 item()
的工作原理?),还是这两个值之间实际上存在根本差异?
浮点数从来都不是精确的,由于这些数字在计算机内存中的存储方式(作为 2 的幂的总和),它们表示近似值。
所以,第一个想法是:你的数字几乎永远不会在足够长的精度下准确。
Python 浮点数使用 64 位,因此
89.995
实际上是:
from decimal import Decimal
Decimal(arr[0].item())
# Decimal('89.9950000000000045474735088646411895751953125')
转换为 32 位时,您实际上会损失精度:
Decimal(arr[0].astype(np.float32).item())
# Decimal('89.99500274658203125')
您可能应该
round
将您的数字设置为所需的精度:
round(arr[0].item(), 3)
# 89.995
89.995
,即使这不是实际存储的数字。.item()
时,float32 会转换回“本机”Python 浮点,它始终是 float64。89.995
得到的数字相同,因此打印方式不同。因此,89.995 和您看到的数字是相同的数字,因为它们映射到与 float32 相同的位模式。
我们可以使用
struct
模块进行测试:
>>> import struct
>>> struct.pack('>f', -89.995)
b'\xc2\xb3\xfdq'
>>> struct.pack('>f', -89.99500274658203)
b'\xc2\xb3\xfdq'