Skip to content

Instantly share code, notes, and snippets.

@Code-Hex
Created February 9, 2022 15:42
Show Gist options
  • Select an option

  • Save Code-Hex/b113083b9631f63de9b9ddc72e8c703e to your computer and use it in GitHub Desktop.

Select an option

Save Code-Hex/b113083b9631f63de9b9ddc72e8c703e to your computer and use it in GitHub Desktop.

Revisions

  1. Code-Hex created this gist Feb 9, 2022.
    129 changes: 129 additions & 0 deletions bit_test.go
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,129 @@
    package bit

    import (
    "math"
    "testing"
    )

    // SignExtend は a の値を bitSize で指定される値を解釈し、変換したものを返します。
    // a の値は 32bit 以下の任意のbitSizeの値が入ってくる可能性があります。
    // unsignedが入ってくる可能性は考慮されていません。(仕様外)
    func SignExtend(a uint32, bitSize uint32) int32 {
    // TODO: オーバーフロー時にエラーを返す?
    // https://go.dev/play/p/YRkiziciA2g

    // 指定されたビットにおける負数か判定し、負数の場合は32ビットに対して足りないビットを埋める

    // 1<<(bitSize-1) の部分、bitSize = 8 の場合
    // 0b00000000_00000000_00000000_00000001 << (8 - 1)
    // 0b00000000_00000000_00000000_10000000
    //
    // 1<<(bitSize-1) <= a はこのようになる
    // 0b00000000_00000000_00000000_10000000 < a
    //
    // aがbitSize=8における-10のとき
    // 0b11110110
    //
    // uint32で入ってくるのでこうなる
    // 0b00000000_00000000_00000000_11110110
    //
    // 1<<(bitSize-1) <= a は最終的にこうなる
    // 0b00000000_00000000_00000000_10000000 < 0b00000000_00000000_00000000_11110110
    //
    // なので a は bitSize=8 における負数である、として負数用の処理をする

    if 1<<(bitSize-1) <= a {
    // やりたいことは足りないビットを埋めること
    // もとの値を 0b00000000_00000000_00000000_11110110
    // こうしたい 0b11111111_11111111_11111111_11110110
    // そのため・・・
    // こういうマスクをつくって 0b11111111_11111111_11111111_11111111
    // bitSize分シフト(8の場合) 0b11111111_11111111_11111111_00000000
    // もとの値と | すると 0b11111111_11111111_11111111_11110110
    // -> 足りていないビットが埋まった

    return int32(a | (math.MaxUint32 << bitSize))
    }

    return int32(a)
    }

    // --- FAIL: TestSignExtend (0.00s)
    // --- FAIL: TestSignExtend/#00 (0.00s)
    // /Users/codehex/go/src/github.com/Code-Hex/sign/bit_test.go:88: (bit.args{a:0xf6, bitSize:0x8}) want -10 but got 246
    // --- FAIL: TestSignExtend/#02 (0.00s)
    // /Users/codehex/go/src/github.com/Code-Hex/sign/bit_test.go:88: (bit.args{a:0xe38, bitSize:0xc}) want -456 but got 3640
    // https://www.rapidtables.com/convert/number/binary-to-hex.html
    func TestSignExtend(t *testing.T) {
    type args struct {
    a uint32
    bitSize uint32
    }

    cases := []struct {
    name string
    args args
    want int32
    }{
    {
    // https://ja.wikipedia.org/wiki/%E7%AC%A6%E5%8F%B7%E6%8B%A1%E5%BC%B5
    args: args{
    a: 0b11110110, // 8bit, -10 // 2の補数表現(ビット反転 + 1) 神
    bitSize: 8,
    },
    want: -10,
    },
    {
    args: args{
    a: 0b00001010, // 8bit, 10
    bitSize: 8,
    },
    want: 10,
    },
    {
    args: args{
    a: 0b1110_00111000, // 12bit, -456??
    bitSize: 12,
    },
    want: -456, // 0b0001_11000111 + 1 == 0b0001_11001000
    },
    {
    args: args{
    a: math.MaxInt32, // 32bit, max int32
    bitSize: 32,
    },
    want: math.MaxInt32,
    },
    {
    args: args{
    a: 0b10000000_00000000_00000000_00000000, // 32bit, min int32
    bitSize: 32,
    },
    want: math.MinInt32,
    },
    {
    args: args{
    a: 0b00000000_00000000_00000000_10000000,
    bitSize: 8,
    },
    want: math.MinInt8,
    },
    {
    args: args{
    a: 0,
    bitSize: 8,
    },
    want: 0,
    },
    }
    for _, tc := range cases {
    tc := tc
    t.Run(tc.name, func(t *testing.T) {
    got := SignExtend(tc.args.a, tc.args.bitSize)
    if tc.want != got {
    t.Errorf("(%#v) want %d but got %d", tc.args, tc.want, got)
    }
    })
    }

    }