向下转换浮点数时如何解释 numpy.ndarray.item() 返回的值

问题描述 投票:0回答:2

我使用空间数据,并且经常拥有最多只需要精确到小数点后几位的坐标,例如

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()
的工作原理?),还是这两个值之间实际上存在根本差异?

python numpy casting floating-point
2个回答
0
投票

浮点数从来都不是精确的,由于这些数字在计算机内存中的存储方式(作为 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

0
投票
  1. 数字 89.995 无法用二进制精确表示。存储为 float64 的数字实际上是 0.99499999999999999555910790149937383830547332763671875。
  2. 在打印数字时,Python 会“作弊”一点,并打印一个最小长度的数字字符串,该字符串将转换回相同的数字。因此,它会打印
    89.995
    ,即使这不是实际存储的数字。
  3. 转换为 float32 时,会丢失 29 位有效数字,这意味着实际存储的数字现在与 89.995 的差异更大。
  4. 当您执行
    .item()
    时,float32 会转换回“本机”Python 浮点,它始终是 float64。
  5. 这个 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'
© www.soinside.com 2019 - 2024. All rights reserved.