小能豆

从 IEEE32 浮点数到 32 位整数 numpy 数组(例如:音频 .wav 文件)

py

[-1, +1]我读取了一些以IEEE32 浮点数存储的数据

A = numpy.fromstring(data, dtype = numpy.float32)

但是我不想将数组保留为float32,而是保留为 32 位整数(以 为单位[-2^31, +2^31-1])。

我尝试简单地做:

A = numpy.fromstring(data, dtype = numpy.int32)   # that's wrong!

但它给出了一个糟糕的结果。(可能是由于乘法常数错误,或者是其他原因?)

如何将 [-1,1] 内的 IEEE32 浮点数数组读入 32 位整数数组[-2^31, +2^31-1]


PS:这是可行的,但我想避免这种幼稚的方法:

A = numpy.fromstring(data, dtype = numpy.float32)
A *= 2^31    
A = int(A)   # convert the data type to int

如果可能的话,因为我想象有一个更聪明的方法来做到这一点,无需乘法,而只需按位执行…


阅读 20

收藏
2025-01-01

共1个答案

小能豆

要将存储为 IEEE 32 位浮点数(float32)的数组 [-1, +1] 转换为对应的 32 位整数(int32)数组 [-2^31, +2^31-1],可以使用按位操作(避免显式乘法)。这可以通过以下步骤实现:

核心思想

将浮点数通过视图转换为整数。由于 float32int32 都是 32 位宽的类型,可以利用 numpy 的 .view() 方法在内存中重解释数据类型,从而避免显式的逐个乘法和数据拷贝。

实现代码

import numpy as np

# 假设数据是以 IEEE float32 形式存储的 [-1, +1] 浮点数组
data = np.random.uniform(-1, 1, 10).astype(np.float32).tobytes()

# 读取数据为 float32 数组
A = np.frombuffer(data, dtype=np.float32)

# 将数据从 float32 转换为 int32 范围 [-2^31, +2^31-1]
B = np.round(A * (2**31 - 1)).astype(np.int32)

# 输出结果
print("原始浮点数据:", A)
print("转换后的整数数据:", B)

为什么 .astype(np.int32) 不直接起作用?

简单地将 float32 直接转为 int32,数据会被截断,而不是映射到目标范围。这是因为:
1. float32 的值范围与 int32 不一致。
2. 转换时需要将 [-1, +1] 按比例映射到 [-2^31, +2^31-1]

为什么需要乘法映射?

浮点数的范围是 [-1, 1],而整数的范围是 [-2^31, 2^31-1]。直接按位转换会导致错误结果,除非数据本身已经编码了这种比例关系。乘法确保数据被正确映射。

按位操作(如果数据以比例方式存储)

如果数据已经以比例编码,可以通过直接 reinterpret_cast 的方式操作:

# 直接视图转换(仅适用于特定数据布局)
B = A.view(np.int32)

但请注意,这种方法仅适用于 原始数据已经存储为符合目标整数表示的布局 的场景。如果你的数据不是这种比例编码,那么使用乘法映射的方式是必要的。

2025-01-01