技術

【Golang】package strconvのintSize = 32 << (∧uint(0) >> 63)は何をしているのか

投稿日:

こんにちは

Goのstrconvのパッケージを読んでたらintSizeというものがありました。

const intSize = 32 << (^uint(0) >> 63)

intSizeはAtoiメソッド内で使用されています。

if intSize == 32 && (0 < sLen && sLen < 10) || intSize == 64 && (0 < sLen && sLen < 19)

見た感じintSizeには32か64が代入されるであろうということは分かるのですが、なぜその式になるのかが分からなったので調べてみました。

<<>>はビット演算子です。<<が左シフト演算で>>が右シフト演算です。
^はビット演算(XOR)です。

使い方はこんな感じ。

package main

import "fmt"

const (
	A uint8 = 44
)

func main() {
	a := fmt.Sprintf("2進数: %b, 10進数: %d", A, A)
	fmt.Println(a)
	// 2進数: 00101100, 10進数: 44

	l := A << 2
	b := fmt.Sprintf("2進数: %b, 10進数: %d", l, l)
	fmt.Println(b)
	// 2進数: 10110000, 10進数: 176

	r := A >> 2
	c := fmt.Sprintf("2進数: %b, 10進数: %d", r, r)
	fmt.Println(c)
	// 2進数: 1011, 10進数: 11

	d := fmt.Sprintf("2進数: %b, 10進数: %d", ^A, ^A)
	fmt.Println(d)
	// 2進数: 11010011, 10進数: 211
}

^は整数演算子としても用意されていて反転の意味になります。44の2進数、00101100を反転すると11010011になります。

公式ではこのように書かれています。

^x bitwise complement is m ^ x with m = “all bits set to 1” for unsigned x and m = -1 for signed x

mには毎回1がセットされ、1ビット毎に排他的論理和演算を行っています。

排他的論理和演算は

0 XOR 0 = 0
0 XOR 1 = 1
1 XOR 0 = 1
1 XOR 1 = 0

という性質を持ちます。

先程の^Aでいうと

1 ^ 0 = 1
1 ^ 0 = 1
1 ^ 1 = 0
1 ^ 0 = 1
1 ^ 1 = 0
1 ^ 1 = 0
1 ^ 0 = 1
1 ^ 0 = 1

を内部で行っており、結果11010011となります。

ここまでは分かれば式で何が行われているのかが分かります。
それでは元のソースコードに戻ります。

const intSize = 32 << (^uint(0) >> 63)

最初に実行されるのは

(^uint(0) >> 63)

の部分でその後に

32 << 上記の計算結果

が実行されます。

uintは環境依存で、32bitか64bitになります。
下記の2つがそれぞれの計算結果になります。

uintが32bitの場合

uint(0) 32bit0埋めにする
0000 0000 0000 0000 0000 0000 0000 0000

^uint(0) 反転する
1111 1111 1111 1111 1111 1111 1111 1111

^uint(0) >> 63 右シフト演算で63bitシフトさせる。結果0になる
0000 0000 0000 0000 0000 0000 0000 0000

左シフト演算
32 << 0 = 32
intSize = 32

uintが64bitの場合

uint(0) 64bit0埋めにする
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000

^uint(0) 反転する
1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111

^uint(0) >> 63 右シフト演算で63bitシフトさせる。結果1になる
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0001

左シフト演算
32 << 1 = 64
intSize = 64

結果intSizeには32か64が代入されます。
スマート!!

最初見た時はよく分からなかったのですが、調べてみたらとても面白かったです。
引き続きGoのソースリーディングはしていくので、また面白いものがあったらブログに書いていこうと思います。

参考URL
The Go Programming Language Specification

-技術

執筆者:


comment

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください

関連記事

どの端末で見ても、要素を上下左右の中央に配置する!

こんにちは。たなかです。 最近はスマホで表示するWebアプリの開発をさせてもらっ …

[Rails]「どのブラウザからのアクセスか」を判別する方法

こんにちは。たなかです。 前回以下のような記事を書きました。   [R …

no image

【ionic】Androidビルド失敗!Multiple dex files define

どうも、中田です。 久しぶりにionicでビルドしたらAndroidビルドに失敗 …

セレクトボックスにfont-awesomeのアイコンを使うときは注意が必要。

セレクトボックスの中にfont-awesomeのアイコンを表示したい。 そんなと …

no image

【Rails】helperからbrタグを含めた文字列を返したい時

こんにちは プライベートではもっぱらRailsを触っています。 触ってからそんな …