Buka operator << dan >>

124

Bisakah seseorang menjelaskan kepada saya penggunaan <<dan >>di Go? Saya rasa ini mirip dengan beberapa bahasa lain.

brianoh
sumber

Jawaban:

169

Definisi super (mungkin lebih) yang disederhanakan hanya <<digunakan untuk "kali 2" dan >>untuk "dibagi 2" - dan angka setelahnya adalah berapa kali.

Begitu n << xjuga dengan "n kali 2, x kali". Dan y >> zadalah "y dibagi 2, z kali".

Misalnya, 1 << 5adalah "1 kali 2, 5 kali" atau 32. Dan 32 >> 5adalah "32 dibagi 2, 5 kali" atau 1.

Semua jawaban lain memberikan definisi yang lebih teknis, tetapi tidak ada yang menjelaskannya secara blak-blakan dan saya pikir Anda mungkin menginginkannya.

Peter Oram
sumber
7
Ini jawaban yang bagus. Ini benar-benar memantapkannya di kepala saya, terima kasih.
Sam Orozco
2
Beginilah seharusnya jawaban.
Utsav Gupta
103

Dari spesifikasi di http://golang.org/doc/go_spec.html , tampaknya setidaknya dengan bilangan bulat, ini adalah pergeseran biner. misalnya, biner 0b00001000 >> 1 akan menjadi 0b00000100, dan 0b00001000 << 1 akan menjadi 0b00010000.


Go tampaknya tidak menerima notasi 0b untuk bilangan bulat biner. Saya hanya menggunakannya sebagai contoh. Dalam desimal, 8 >> 1 adalah 4, dan 8 << 1 adalah 16. Menggeser ke kiri dengan satu sama dengan mengalikan dengan 2, dan menggeser ke kanan dengan satu sama dengan membagi dua, membuang sisa.

jcomeau_ictx
sumber
4
Jawaban yang bagus. Sangat masuk akal ketika saya berpikir bahwa saya melihat ini dalam kode yang berhubungan dengan pangkat 2 (1 << power = 2 ^ power)
Stephen Smith
6
Saya pikir ini akan menjadi persamaan lengkap: (x << n == x * 2 ^ n) (x >> n == x * 2 ^ (- n))
MondayPaper
jawaban yang bagus, saya menggeser biner tampak merepotkan pada awalnya tetapi mengubah nilai menjadi desimal dengan
pangkat
31

Operator << dan >> adalah Operator Aritmatika Go .

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

Operator shift menggeser operan kiri dengan hitungan shift yang ditentukan oleh operan kanan. Mereka mengimplementasikan pergeseran aritmatika jika operan kiri adalah bilangan bulat bertanda dan pergeseran logis jika itu adalah bilangan bulat tak bertanda. Hitungan shift harus berupa bilangan bulat unsigned. Tidak ada batasan atas jumlah shift. Pergeseran berperilaku seolah-olah operan kiri digeser n kali sebesar 1 untuk hitungan shift n. Akibatnya, x << 1 sama dengan x * 2 dan x >> 1 sama dengan x / 2 tetapi terpotong menuju tak terhingga negatif.

peterSO
sumber
10

Mereka pada dasarnya adalah operator Aritmatika dan yang sama dalam bahasa lain di sini adalah Contoh dasar PHP, C, Go

PERGILAH

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 Demo

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 Demo

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);
}

Demo PHP

Mereka semua akan menghasilkan

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 
Baba
sumber
7

Go << dan >> mirip dengan shift (yaitu: pembagian atau perkalian dengan pangkat 2) dalam bahasa lain, tetapi karena Go adalah bahasa yang lebih aman daripada C / C ++ ia melakukan beberapa pekerjaan tambahan ketika jumlah shift berupa angka .

Instruksi shift pada CPU x86 hanya mempertimbangkan 5 bit (6 bit pada 64-bit CPU x86) dari hitungan shift. Dalam bahasa seperti C / C ++, operator shift diterjemahkan menjadi satu instruksi CPU.

Kode Go berikut

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

cetakan

0
0

sementara program C / C ++ akan mencetak

5
20

sumber
3
Untuk operator shift C dan C ++, "Perilaku tidak ditentukan jika operan kanan negatif, atau lebih besar dari atau sama dengan panjang bit dari operan kiri yang dipromosikan." Standar C dan C ++ tidak menjamin bahwa program C dan C ++ akan mencetak 5 dan 20.
peterSO
@peterSO: Ya, Anda benar. Sudut pandang saya adalah bahwa setiap standar bahasa pemrograman harus memiliki implementasi konkret pada CPU yang konkret. Dalam konteks satu keluarga CPU (x86-32), perilaku semua compiler C / C ++ adalah (dapat diharapkan) sama. Alasan untuk ini adalah bahwa memancarkan tepat 1 instruksi SHL / SHR / etc untuk mengimplementasikan operator shift adalah hal terbaik yang dapat dilakukan oleh compiler C / C ++ yang mengoptimalkan ketika konteksnya tidak memberitahukan apapun tentang 'x' dan 'y'. Dan, jika kompilator mengetahui fakta bahwa kode tersebut memiliki perilaku yang tidak ditentukan, ia harus memberi tahu pengguna tentang hal itu.
2
Saya tidak setuju. Anda harus menulis kode portabel. Baik Linux dan Windows berjalan di ARM. Berfokus pada satu keluarga CPU adalah rabun dekat. Juga, y adalah variabel. Faktanya, compiler tidak memiliki pengetahuan tentang nilai runtime sebenarnya.
peterSO
@Atom Terlepas dari bahasa yang sama sekali tidak memberikan jaminan tentang apa yang akan terjadi, perilaku tidak terdefinisi cenderung bervariasi bahkan pada satu mesin dengan kompiler tunggal, jika misalnya Anda mengubah opsi kompilasi (mis. Build yang dioptimalkan). Mengandalkan dengan cara apa pun adalah IMO yang salah dan berbahaya.
Paul Hankin
@Anonymous Ya, tapi itu hanya teori. Dapatkah Anda memberikan contoh konkret di mana mengubah opsi kompilasi mengarah ke perilaku yang berbeda dari <<atau >>dalam C / C ++?
6

<<adalah shift kiri. >>adalah pergeseran kanan yang memperpanjang tanda ketika operan kiri adalah bilangan bulat bertanda, dan pergeseran kanan yang memperpanjang nol ketika operan kiri adalah bilangan bulat yang tidak bertanda.

Untuk lebih memahami >>pikirkan

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

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

Jadi ketika diterapkan ke bilangan bulat tak bertanda, bit di sebelah kiri diisi dengan nol, sedangkan bila diterapkan ke bilangan bulat bertanda, bit di sebelah kiri diisi dengan bit paling kiri (yaitu 1 ketika bilangan bulat bertanda negatif sesuai 2 melengkapi).

Mike Samuel
sumber
3

Dalam matematika desimal , saat kita mengalikan atau membagi dengan 10 , kita memberi pengaruh pada angka nol di ujung angka.

Dalam biner , 2 memiliki efek yang sama. Jadi kami menambahkan nol di akhir, atau menghapus digit terakhir

robert king
sumber