Created
February 9, 2022 15:42
-
-
Save Code-Hex/b113083b9631f63de9b9ddc72e8c703e to your computer and use it in GitHub Desktop.
@sters と一緒に学んだ符号拡張をコードかする方法
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
} | |
}) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
最適解です