

posix shell だけでどこまで計算できるものなのかを知りたいと思い、 bit 演算がどうやったら実現できるのか知りたいと思いました。(特に、
sha256/md5 などを実装してみようとしていた)

32 bit の right rotation bit shift 演算を実現したいです。これは、どうやったらできるでしょうか。 shell には
[arithmetic
expansion](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_04)
があり、数値型としては signed long は保証されていること、 bit 演算子たちがあることから、たぶん実現できそうだ、とは思っています。しかし、
long の bit 長って取得できたんだっけ、それをふまえて正しい bit 演算って何なんだっけ、と思っているので、質問しています。


CC BY-SA 3.0
2017-12-21T17:02:26.903
40463
2020-03-08T10:13:45.200
754
question
sh posix
posix shell にて 32bit right rotation を実現したい


何をやりたいのかいまひとつわかりませんが、32 bit 整数のビットのシフト、ローテートならこんな感じでしょうか。(効率等は考えていません)

[code]

    #!/bin/sh
    
    ## 32 bit 整数の MSB
    msb=2147483648
    ## 33 bit 整数の MSB
    msbx2=$((msb*2))
    
    ## 32 bit を越える整数を扱えるかどうかのテスト
    [ $msbx2 -gt $msb ] || exit 1
    
    while read v; do
      ## 32 bit 整数に丸める
      v=$((v % msbx2))
      printf 'input         %8x\n' $v
      printf 'right shift:  %8x\n' $(( v / 2 ))
      printf 'left shift:   %8x\n' $(( v * 2 % msbx2 ))
      printf 'right rotate: %8x\n' $(( v / 2 + v % 2 * msb))
      printf 'left rotate:  %8x\n' $(( v * 2 % msbx2 + v / msb))
    done
    
[/code]


CC BY-SA 3.0
2017-12-21T18:37:37.417
40466
2017-12-21T18:37:37.417
3061
40463
answer


# 【 ビット演算によるright rotation】

ビット演算を使用したright rotationを`bash`で実装してみました。

**【コード】**

[code]

    #!/bin/bash
    MAX_BIT_NUM=64
    func(){
        BIT_NUM=$1
        n=$2
        data=$3
        printf "BIT_NUM=%d data=%s n=%-2d " ${BIT_NUM} ${data} ${n}
    
        DATA_MASK=$((  ~((-1)<<(BIT_NUM))  ))
        if [ ${DATA_MASK} = 0 ]; then DATA_MASK=-1; fi  #over flow
        RIGHT_MASK=$((~(-1<<n)))
        LEFT_MASK=$(((-1<<n)&DATA_MASK))
    
        #範囲外bitクリア
        data=$((data&DATA_MASK))
        #rightデータ退避
        right=$((data&RIGHT_MASK))
        #nビット右シフト
        data=$((data>>n))
        #ローテートする部分を0クリア
        data=$(( data&(~(RIGHT_MASK<<(BIT_NUM-n))) ))
        #退避したrightデータをローテートしてセット
        data=$((  data|(right<<(BIT_NUM-n))  ))
        printf "rotete data=0x%016x(%d)\n" ${data} ${data}
    }
    
[/code]

**【実行結果】**

[code]

    BIT_NUM=32 data=16#a0b0c0d0 n=0  rotete data=0x00000000a0b0c0d0(2695938256)
    BIT_NUM=32 data=16#a0b0c0d0 n=1  rotete data=0x0000000050586068(1347969128)
    BIT_NUM=32 data=16#a0b0c0d0 n=2  rotete data=0x00000000282c3034(673984564)
    BIT_NUM=32 data=16#a0b0c0d0 n=3  rotete data=0x000000001416181a(336992282)
    BIT_NUM=32 data=16#a0b0c0d0 n=4  rotete data=0x000000000a0b0c0d(168496141)
    BIT_NUM=32 data=16#a0b0c0d0 n=31 rotete data=0x00000000416181a1(1096909217)
    BIT_NUM=32 data=16#a0b0c0d0 n=32 rotete data=0x00000000a0b0c0d0(2695938256)
    BIT_NUM=64 data=16#a0b0c0d0a0b0c0d0 n=0  rotete data=0xa0b0c0d0a0b0c0d0(-6867777429458337584)
    BIT_NUM=64 data=16#a0b0c0d0a0b0c0d0 n=4  rotete data=0x0a0b0c0d0a0b0c0d(723685415265700877)
    BIT_NUM=64 data=16#a0b0c0d0a0b0c0d0 n=8  rotete data=0xd0a0b0c0d0a0b0c0(-3413534175366434624)
    BIT_NUM=64 data=16#a0b0c0d0a0b0c0d0 n=31 rotete data=0x416181a1416181a1(4711189214792876449)
    BIT_NUM=64 data=16#a0b0c0d0a0b0c0d0 n=32 rotete data=0xa0b0c0d0a0b0c0d0(-6867777429458337584)
    
[/code]

# 【 整数のビット長】

`bash`における`long`がどういうものか分かっていませんが、整数のbit長をカウントしてみました。  
**結果** は **64** でした。

**【コード】**

[code]

    #!/bin/bash
    count=0
    for ((d=1; d != 0; d<<=1))
    do
        ((count+=1))
    done
    printf "count=%d\n" ${count}
    
[/code]

* * *

# 【使用したbashのバージョン】

GNU bash, バージョン 4.4.20(1)-release (x86_64-pc-linux-gnu)


CC BY-SA 4.0
2020-03-08T10:13:45.200
63663
2020-03-08T10:13:45.200
35558
40463
answer