반응형
참고 자료
https://docs.scipy.org/doc/numpy/user/basics.byteswapping.html
파이썬 버전 3.7 기준
NumPy 버전 1.16 기준
본 포스팅에서는 NumPy에서의 Byte-swapping을 다룬다.
NumPy에서의 Byte-swapping
바이트스와핑 개요
바이트스와핑 개요
○ ndarray는 메모리에 데이터로 파이썬 배열 인터페이스를 제공해주는 오브젝트이다.
○ 사용자가 배열을 사용해서 보길 원하는 메모리와 파이썬을 돌리는 컴퓨터와 같은 바이트 순서(Byte ordering)가 아닌 경우가 종종있다.
▷ 대표적으로 Intel Pentium와 같은 리틀 엔디언(Little-endian) CPU에서 빅 엔디언(Big-endian)에서 작성된 데이터를 불러올 경우 등이 있다.
○ 바이트에 대해 직접 빅엔디안 컴퓨터에서 작성된 파일에서 4바이트를 불러온다고 예를 들어본다면,
▷ 4바이트면 16 비트이다.
▷ 빅엔디안 장치에서는 2바이트 정수형은 최상위바이트(MSB, Most Significant Byte)에 먼저 저장되고 그 다음 최하위바이트(LSB, Least Significant Byte)에 저장된다. 그러므로 메모리 순서는 다음과 같다.
① MSB 정수 1
② LSB 정수 1
③ MSB 정수 2
④ LSB 정수 2
바이트스와핑의 예제
○ 4바이트에서 2바이트씩 가지는 정수를 만든다고 가정한다.
○ 두개의 정수가 1과 770로 가정을 하여 예를 들어볼 경우
▷ 1은 0*256 + 1이기 때문에 각 바이트에는 0과 1이 들어간다.
▷ 770은 3*256^1 + 2 이기 때문에 각 바이트에는 3, 2라는 값이 들어가게 된다.
▷ 즉 각 바이트에 들어가는 값은 0, 1, 3, 2이다.
○ 이 경우 파일에 이 바이트 값을 직접들어가게 하기 위해서는 아래와 같이 입력할 수 있다.
▷ 여기서 \x00은 1바이트에서 0를 의미하며, 나머지 \x01, \는03, \x02는 마찬가지로 1바이트에서 1, 3, 2를 각각 의미한다.
○ ndarray를 이용하여 위의 정수값을 바이트에 직접 입력하고자하면 아래와 같이 할 수 있다.
▷ 이 경우 이 메모리 주변에 배열을 만들 수 있고, 이 데이터는 16 bit이며 빅엔디안을 가지도록 설정할 수 있다.
바이트 입력)
# 바이트 데이터 정의
In[19]:byte_data = b'\x00\x01\x03\x02'
# 바이트 데이터를 입력
In[20]: byte_arr_big = np.ndarray(shape=(2), dtype=">i2", buffer=byte_data)
#바이트 데이터 결과
In[21]: byte_arr_big[0]
Out[21]: 1
In[22]: byte_arr_big[1]
Out[22]: 770
※ 여기서 >i2에서 >는 빅엔디안을 의미하며, (<는 리틀엔디안을 의미한다.), i2는 부호있는 2바이트 정수를 의미한다.
○ 위의 데이터를 리틀엔디안에서 부호없는 4바이트로 데이터로 표현하면 아래와 같다.
▷ 리틀엔디언의 경우 위의 데이터가 0*256^0 + 1*256^1 + 3*256^2 + 2*256^3이기 때문에 33751296란 값이 나온다.
바이트 입력)
In[23]: byte_arr_little = np.ndarray(shape=(1), dtype="<u4", buffer=byte_data)
In[24]: byte_arr_little
Out[24]: array([33751296], dtype=uint32)
※ 주의
스칼라에는 바이트 순서에 대한 정보가 입력되지 않으므로 스칼라를 직접 추출하여 정수를 반환할 경우 원래 바이트 순서로 반환된다. 따라서 아래와 같은 상황이 벌어질 수도 있다.
In[28]: byte_arr_big[0].dtype.byteorder == byte_arr_little[0].dtype.byteorder
Out[28]: True
바이트 순서 변환
○ 배열과 메모리의 바이트 순서간에 영향을 미치는 방법으로는 크게 2가지가 있다.
① 배열의 dtype에서 바이트 순서 정보를 변경하여, 이것이 다른 바이트 순서에서 근본적인 데이터가 해석되게 하는 것이 있다. 이것은 arr.newbyteorder()로 수행할 수 있다.
② dtype을 그대로 남겨두고, 바이트 데이터의 바이트 순서를 뒤바꾸는 방법이 있다. arr.byteswap()으로 수행이 가능하다.
○ 바이트 순서를 바꿔야할 필요가 있는 공통적인 상황은 다음과 같다.
① 데이터와 dtype 에디안이 매치가 되지 않는 상황에서, 서로 매치시키기 위해 dtype이 바뀌길 원할 경우.
② 데이터와 dtype 에디안이 매치가 되지 않는 상황에서, 서로 매치시키기 위해 데이터를 바꾸는 경우.
③ 데이터와 dtype 에디안이 매치가 되어있는 상황에서, 데이터와 dtype을 둘 다 바꾸는 경우.
①번 경우
○ 이 상황에서는 arr.newbyteorder() 메서드를 이용하여 고칠 수 있다.
사용 예)
# 리틀엔디안에서 빅엔디안으로 바꾸기 위한 예제입력(위의 예제에서 byte_data 입력 활용)
In[34]: not_big_endian = np.ndarray(shape=(2,), dtype='<i2', buffer=byte_data)
In[35]: not_big_endian[0]
Out[35]: 256
# 빅엔디안으로의 변환
In[36]: big_endian = not_big_endian.newbyteorder()
In[37]: big_endian[0]
Out[37]: 1
# 바이트의 비교
In[38]: big_endian.tobytes() == byte_data
Out[38]: True
②번 경우
○ 이 상황에서는 arr.byteswap() 메서드를 활용하면 된다.
사용 예)
# 바이트의 변경, 입력 데이터는 위의 not_big_endian 데이터 활용
In[41]: not_big_endian_byte_change = not_big_endian.byteswap()
In[42]: not_big_endian_byte_change[0]
Out[42]: 1
# 바이트의 비교
In[43]: not_big_endian_byte_change.tobytes() == byte_data
Out[43]: False
③번 경우
○ 이 상황에서는 arr.newbyteorder()과 arr.byteswap()메서드 둘 다 이용하면 된다.
사용 예)
# 바이트와 엔디안의 변경, 입력 데이터는 위의 big_endian 데이터 활용
In[48]: all_change = big_endian.byteswap().newbyteorder()
In[49]: all_change[0]
Out[49]: 1
# 바이트의 비교
In[50]: all_change.tobytes() == byte_data
Out[50]: False
반응형
'Python > NumPy' 카테고리의 다른 글
Structured Array(구조체 배열)의 indexing(인덱싱)과 assignment(배정) - NumPy(10) (0) | 2019.02.24 |
---|---|
Structured Array(구조체 배열)의 개요와 생성 - NumPy(9) (0) | 2019.02.23 |
NumPy(넘파이)에서의 Broadcasting(브로드캐스팅) - NumPy(7) (0) | 2019.02.10 |
NumPy(넘파이)에서의 indexing(인덱싱) - NumPy(6) (0) | 2019.02.08 |
genfromtxt을 통한 배열(array) 생성 상세 - NumPy(5) (0) | 2019.02.03 |
댓글