<<演算子と>>演算子を使用する


124

Go <<との使用法を誰かに説明してもらえ>>ますか?他のいくつかの言語に似ていると思います。

回答:


168

スーパー(おそらくオーバー)の単純化された定義は<<、「2倍」と>>「2で除算」に使用されるもので、その後の数は何回かです。

そうn << xです、「n回2、回×」。そしてy >> z、「yを2で割ったz回」です。

たとえば、1 << 5「1倍2、5倍」または32です。また32 >> 5、「32を2で割って5倍」または1です。

他のすべての答えはより技術的な定義を提供しますが、誰もそれを本当に率直に説明した人はいません。


7
これは素晴らしい答えです。これは本当に頭の中でそれを固めました、ありがとう。
Sam Orozco、

2
これが答えのあるべき姿です。
Utsav Gupta

103

http://golang.org/doc/go_spec.htmlの仕様から、少なくとも整数では、バイナリシフトであるようです。たとえば、バイナリ0b00001000 >> 1は0b00000100、0b00001000 << 1は0b00010000になります。


Goは明らかに2進整数の0b表記を受け入れません。例として使用しただけです。10進数では、8 >> 1は4、8 << 1は16です。左に1シフトすることは2を乗算することと同じで、右に1シフトすることは2で除算することと同じで、残りはすべて破棄されます。


4
すばらしい答えです。私は私が2(1 <<パワー= 2 ^パワー)の力を扱うコードでこれを見ていたことを考えるとき、それは多くの意味を作る
スティーブン・スミス

6
私はこれが完全な方程式になると思います:(x << n == x * 2 ^ n)(x >> n == x * 2 ^(-n))
月曜日ペーパー'19

いい答えですが、最初はバイナリシフトが厄介に思えましたが、値を2の累乗で10進数に変換するとうまくいきます
minhajul

30

<<および>>演算子はGo算術演算子です。

<<   left shift             integer << unsigned integer
>>   right shift            integer >> unsigned integer

シフト演算子は、右のオペランドで指定されたシフト数だけ左のオペランドをシフトします。左のオペランドが符号付き整数の場合は算術シフトを実装し、符号なし整数の場合は論理シフトを実装します。シフト数は符号なし整数でなければなりません。シフト数に上限はありません。シフトは、シフトカウントがnの場合、左のオペランドが1だけn回シフトされるかのように動作します。その結果、x << 1はx * 2と同じで、x >> 1はx / 2と同じですが、負の無限大に切り捨てられます。


10

これらは基本的に算術演算子であり、他の言語でも同じですが、基本的なPHP、C、Goの例です

行く

package main

import (
    "fmt"
)

func main() {
    var t , i uint
    t , i = 1 , 1

    for i = 1 ; i < 10 ; i++ {
        fmt.Printf("%d << %d = %d \n", t , i , t<<i)
    }


    fmt.Println()

    t = 512
    for i = 1 ; i < 10 ; i++ {
        fmt.Printf("%d >> %d = %d \n", t , i , t>>i)
    }

}

GOデモ

C

#include <stdio.h>
int main()
{

    int t = 1 ;
    int i = 1 ;

    for(i = 1; i < 10; i++) {
        printf("%d << %d = %d \n", t, i, t << i);
    }

        printf("\n");

    t = 512;

    for(i = 1; i < 10; i++) {
        printf("%d >> %d = %d \n", t, i, t >> i);
    }    

  return 0;
}

Cデモ

PHP

$t = $i = 1;

for($i = 1; $i < 10; $i++) {
    printf("%d << %d = %d \n", $t, $i, $t << $i);
}

print PHP_EOL;

$t = 512;

for($i = 1; $i < 10; $i++) {
    printf("%d >> %d = %d \n", $t, $i, $t >> $i);
}

PHPデモ

彼らはすべて出力します

1 << 1 = 2 
1 << 2 = 4 
1 << 3 = 8 
1 << 4 = 16 
1 << 5 = 32 
1 << 6 = 64 
1 << 7 = 128 
1 << 8 = 256 
1 << 9 = 512 

512 >> 1 = 256 
512 >> 2 = 128 
512 >> 3 = 64 
512 >> 4 = 32 
512 >> 5 = 16 
512 >> 6 = 8 
512 >> 7 = 4 
512 >> 8 = 2 
512 >> 9 = 1 

7

Goの<<と>>は、他の言語のシフト(つまり、2の累乗による除算または乗算)に似ていますが、GoはC / C ++よりも安全な言語であるため、シフトカウントが数値の場合、追加の作業を行います。

x86 CPUのシフト命令は、シフトカウントの5ビット(64ビットx86 CPUでは6ビット)のみを考慮します。C / C ++のような言語では、シフト演算子は単一のCPU命令に変換されます。

次のGoコード

x := 10
y := uint(1025)  // A big shift count
println(x >> y)
println(x << y)

プリント

0
0

C / C ++プログラムは印刷しますが

5
20

3
CおよびC ++シフト演算子の場合、「右のオペランドが負であるか、昇格された左のオペランドの長さ(ビット単位以上)の場合の動作は未定義です。」CおよびC ++標準規格は、CおよびC ++プログラムは5と20を印刷することを保証するものではありません
peterSO

@peterSO:はい、そうです。私の立場は、各プログラミング言語標準は具体的なCPUで具体的な実装を持たなければならないということです。単一のCPUファミリ(x86-32)のコンテキストでは、すべてのC / C ++コンパイラの動作は同じです(予想される)。この理由は、シフト演算子を実装するために1つのSHL / SHR / etc命令を正確に発行することは、コンテキストが「x」と「y」について何も伝えていない場合に、最適化C / C ++コンパイラーが実行できる最善のことです。また、コンパイラーがコードの動作が未定義であることを知っている場合は、ユーザーに通知する必要があります。

2
同意しません。移植可能なコードを書く必要があります。LinuxとWindowsの両方がARMで実行されます。単一のCPUファミリーに焦点を合わせるのは近視眼的です。また、yは変数です。事実、コンパイラは実際のランタイム値を認識していません。
peterSO

@Atom何が起こるかをまったく保証しない言語を除いて、たとえばコンパイルオプションを変更した場合(最適化されたビルドなど)、単一のコンパイラを備えた単一のマシンでも未定義の動作が異なる可能性があります。何らかの形でそれ依存することは、危険なほど間違ったIMOです。
ポール・ハンキン

@匿名はい、しかしそれは理論にすぎません。コンパイルオプションを変更すると異なる動作が発生する具体的な例を教えてください<<か、>>C / C ++で?

6

<<左シフトです。 >>左のオペランドが符号付き整数の場合は符号拡張右シフトであり、左のオペランドが符号なし整数の場合はゼロ拡張右シフトです。

よりよく理解するため>>

var u uint32 = 0x80000000;
var i int32 = -2;

u >> 1;  // Is 0x40000000 similar to >>> in Java
i >> 1;  // Is -1 similar to >> in Java

したがって、符号なし整数に適用した場合、左側のビットはゼロで埋められますが、符号付き整数に適用した場合、左側のビットは左端のビットで埋められます(符号付き整数が2のように負の場合は1になります)。補体)。


3

、小数点数学、我々乗除算10をすることにより、我々は、番号の末尾にゼロをもたらします。

バイナリ2は同じ効果を有します。したがって、最後にゼロを追加するか、最後の桁を削除します

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.