Python 中 NumPy 的字节交换

大小端模式

大端模式(Big-endian):高位字节放在内存的低地址端,低位字节排放在内存的高地址端,即正序排列,高尾端;符号位的判定固定为第一个字节,容易判断正负。

小端模式(Little-endian):低位字节放在内存的低地址端,高位字节排放在内存的高地址端,即逆序排列,低尾端;强制转换数据不需要调整字节内容

字节排序和 ndarrays 简介

ndarrays 是一个为内存中的数据提供 python 数组接口的对象。

假定从大端模式机器写入的文件中加载了 4 个字节。我知道这 4 个字节代表两个 16 位整数。在大端模式机器上,首先以最高有效字节(MSB)存储双字节整数,然后存储最低有效字节(LSB)。因此字节按内存顺序排列:

MSB整数1,LSB整数1,MSB整数2,LSB整数2

假设两个整数实际上是 1 和 770。因为 770 = 256 * 3 + 2,内存中的 4 个字节将分别包含:0,1,3,2。我从文件加载的字节将包含这些内容:

>>> big_end_buffer = bytearray([0,1,3,2])
>>> big_end_buffer
bytearray(b'\x00\x01\x03\x02')

对这个内存创建一个数组,并告诉 numpy 有两个整数,并且它们是 16 位和 Big-endian:

>>> import numpy as np
>>> big_end_arr = np.ndarray(shape=(2,),dtype='>i2', buffer=big_end_buffer)
>>> big_end_arr[0]
1
>>> big_end_arr[1]
770

注意上面的数组 dtype > i2。> 表示 big-endian ( < 是 Little-endian ),i2 表示‘有符号的 2 字节整数。例如,如果是单个无符号 4 字节小端整数,则 dtype 字符串将为 <u4。

>>> little_end_u4 = np.ndarray(shape=(1,),dtype='<u4', buffer=big_end_buffer)
>>> little_end_u4[0] == 1 * 256**1 + 3 * 256**2 + 2 * 256**3
True

但标量当前不包含字节顺序信息,因此从数组中提取标量将返回本机字节顺序的整数。因此:

>>> big_end_arr[0].dtype.byteorder == little_end_u4[0].dtype.byteorder
True

更改字节顺序

从介绍中可以想象,有两种方法可以影响数组的字节顺序与它所查看的底层内存之间的关系:

1.  arr.newbyteorder():更改数组 dtype 中的字节顺序信息,以便将基础数据解释为不同的字节顺序。

2. arr.byteswap():更改基础数据的字节顺序,保留dtype解释。

什么情况需要更改字节顺序:

1. 数据和 dtype 字节顺序不匹配,希望更改dtype以使其与数据匹配。

2. 数据和 dtype 字节顺序不匹配,希望交换数据以使它们与dtype匹配

3. 数据和 dtype 字节顺序匹配,希望交换数据和dtype来反映这一点

数据和dtype字节顺序不匹配,更改dtype以匹配数据

假定不匹配的数据如下:

>>> wrong_end_dtype_arr = np.ndarray(shape=(2,),dtype='<i2', buffer=big_end_buffer)
>>> wrong_end_dtype_arr[0]
256

解决方法为更改 ​​dtype,以给出正确的字节顺序:

>>> fixed_end_dtype_arr = wrong_end_dtype_arr.newbyteorder()
>>> fixed_end_dtype_arr[0]
1

此时,内存中的数组未更改:

>>> fixed_end_dtype_arr.tobytes() == big_end_buffer
True

数据和类型字节顺序不匹配,更改数据以匹配dtype

可以在内存写入需要特定字节排序的文件。

>>> fixed_end_mem_arr = wrong_end_dtype_arr.byteswap()
>>> fixed_end_mem_arr[0]
1

此时,内存为:

>>> fixed_end_mem_arr.tobytes() == big_end_buffer
False

数据和dtype字节序匹配,交换数据和dtype

假定存在正确指定的数组 dtype,但需要数组在内存中具有相反的字节顺序,并且您希望 dtype 匹配以便数组值有意义。在这种情况下,需执行上述两个操作:

>>> swapped_end_arr = big_end_arr.byteswap().newbyteorder()
>>> swapped_end_arr[0]
1
>>> swapped_end_arr.tobytes() == big_end_buffer
False

使用 ndarray astype 方法可以更简单地将数据转换为特定的 dtype 和字节顺序:

>>> swapped_end_arr = big_end_arr.astype('<i2')
>>> swapped_end_arr[0]
1
>>> swapped_end_arr.tobytes() == big_end_buffer
False

参考资料:

1. NumPy 官方文档:https://numpy.org/devdocs/

发布了77 篇原创文章 · 获赞 5 · 访问量 4940

猜你喜欢

转载自blog.csdn.net/SAKURASANN/article/details/102657100
今日推荐