LoginSignup
1
0

More than 3 years have passed since last update.

numpyでシフト演算を使って符号無し⇒符号有りに変換する

Last updated at Posted at 2021-02-26

TL;DR

numpyの符号無しのndarrayをシフト演算を使って符号有りに変換する方法の紹介です.

numpyのシフト演算

numpyは要素毎にシフト演算することができる.
シフト演算も例外できる.

>>> import numpy as np
>>> val = np.arange(5)
>>> val
array([0, 1, 2, 3, 4])
>>> val << 4
array([ 0, 16, 32, 48, 64], dtype=int32)
>>> val >> 1
array([0, 0, 1, 1, 2], dtype=int32)

符号無し => 符号有りに変換

astype

astype関数を使って符号無しから符号有りに変換することはできる.
8bitであれば,uint8からint8に変換すれば問題ない(16bit/32bit/64bitも同様).

>>> import numpy as np
>>> val = np.asarray([255, 0, 127, 128], dtype=np.uint8)
>>> val
array([255,   0, 127, 128], dtype=uint8)
>>> val.astype(np.int8)
array([  -1,    0,  127, -128], dtype=int8)

しかし,4bitや12bitといったデータを扱う場合こうはいかない.
(4bitや12bitといった型は存在しないため)
要素数が少ない場合は2進変換->10進変換をfor文でループしたり,frompyfuncを使えば良いが,要素数が多いと時間がかかる(numpyの意味がない).
np.whereを使うとしても要素数が多いと時間はかかってくる(インデックスアクセスが遅くなる).

そこでシフト演算を使うことで解決を図る.

シフト演算

numpyでは型の上限のbitまで左シフトしてから右シフトすると符号有りに変換される.
最上位bit=符号bitに情報が残るようである.

符号有り8bitで詳しく説明する.

1を2進で表すと以下
1 → 00000001

これを7bit左シフト
000000001 << 7
> 10000000

10進で表すと
10000000 → -128

7bit左シフトした分を右シフト
10000000 >> 7
> 00000001 (理論的にはこっち)
> 10000001 (実際はこっち)

10進で表すと
00000001 → 1
10000001 → -1

つまり,4bitだと8bit,12bitだと16bitで情報を持つことになるので,4bit左シフトして右シフトすると符号有りに変換できる.
(24bitだと32bitなので8bitシフトになる)

>>> import numpy as np
>>> val = np.arange(pow(2, 4), dtype=np.int8)
>>> val
array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15],
      dtype=int8)
>>> val << 4 >> 4
array([ 0,  1,  2,  3,  4,  5,  6,  7, -8, -7, -6, -5, -4, -3, -2, -1],
      dtype=int8)

まとめ

この特性を活かすことで,シフト演算を使って高速に4bitや12bitを符号無しから符号有りに変換できます.
(4bitや12bitといっていますが,何bitでもOKです)
ぜひ試してみてください.

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0