Vai agli operatori << e >>


124

Qualcuno potrebbe spiegarmi l'uso di <<e >>in Go? Immagino sia simile ad altre lingue.

Risposte:


169

La definizione super (forse eccessivamente) semplificata è proprio quella <<usata per "volte 2" e>> è per "diviso per 2" - e il numero dopo è quante volte.

Quindi n << xè "n volte 2, x volte". Ey >> z è "y diviso 2, z volte".

Ad esempio, 1 << 5è "1 per 2, 5 volte" o 32. Ed 32 >> 5è "32 diviso per 2, 5 volte" o 1.

Tutte le altre risposte danno la definizione più tecnica, ma nessuno l'ha esposta in modo davvero schietto e ho pensato che potresti volerlo.


7
Questa è un'ottima risposta. Questo mi ha davvero solidificato nella testa, grazie.
Sam Orozco

2
Ecco come dovrebbero essere le risposte.
Utsav Gupta

103

Dalle specifiche su http://golang.org/doc/go_spec.html , sembra che almeno con i numeri interi, sia uno spostamento binario. ad esempio, il binario 0b00001000 >> 1 sarebbe 0b00000100 e 0b00001000 << 1 sarebbe 0b00010000.


Go apparentemente non accetta la notazione 0b per interi binari. Lo stavo usando solo per l'esempio. In decimale, 8 >> 1 è 4 e 8 << 1 è 16. Spostare a sinistra di uno equivale a moltiplicare per 2 e spostare a destra di uno equivale a dividere per due, scartando qualsiasi resto.


4
Bella risposta. Ha molto senso quando penso che stavo vedendo questo nel codice che trattava di potenze di 2 (1 << potenza = 2 ^ potenza)
Stephen Smith

6
Penso che questa sarebbe l'equazione completa: (x << n == x * 2 ^ n) (x >> n == x * 2 ^ (- n))
MondayPaper

bella risposta, all'inizio lo spostamento binario sembrava fastidioso, ma convertire il valore in decimale con potenze a 2 aiuta bene a ottenerlo
minhajul

31

Gli operatori << e >> sono Operatori Aritmetici .

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

Gli operatori di spostamento spostano l'operando di sinistra del conteggio di spostamento specificato dall'operando di destra. Implementano spostamenti aritmetici se l'operando di sinistra è un numero intero con segno e spostamenti logici se è un numero intero senza segno. Il conteggio dello spostamento deve essere un numero intero senza segno. Non esiste un limite massimo per il conteggio dei turni. Gli spostamenti si comportano come se l'operando di sinistra fosse spostato n volte di 1 per un conteggio degli spostamenti pari a n. Di conseguenza, x << 1 è uguale a x * 2 ex >> 1 è uguale a x / 2 ma troncato verso l'infinito negativo.


10

Sono fondamentalmente operatori aritmetici ed è lo stesso in altre lingue qui è un PHP di base, C, Go Example

PARTIRE

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

Sarebbero usciti tutti

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

I << e >> di Go sono simili ai turni (ovvero: divisione o moltiplicazione per una potenza di 2) in altri linguaggi, ma poiché Go è un linguaggio più sicuro di C / C ++ fa del lavoro extra quando il conteggio dei turni è un numero .

Le istruzioni di spostamento nelle CPU x86 considerano solo 5 bit (6 bit su CPU x86 a 64 bit) del conteggio degli spostamenti. In linguaggi come C / C ++, l'operatore shift si traduce in una singola istruzione della CPU.

Il codice Go seguente

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

stampe

0
0

mentre un programma C / C ++ potrebbe stampare

5
20

3
Per gli operatori di scorrimento C e C ++, "Il comportamento non è definito se l'operando destro è negativo, o maggiore o uguale alla lunghezza in bit dell'operando sinistro promosso." Gli standard C e C ++ non garantiscono che i programmi C e C ++ stamperanno 5 e 20.
peterSO

@peterSO: Sì, hai ragione. Il mio punto di vista è che ogni standard del linguaggio di programmazione deve avere un'implementazione concreta su una CPU concreta. Nel contesto di una singola famiglia di CPU (x86-32), il comportamento di tutti i compilatori C / C ++ è (ci si può aspettare che sia) lo stesso. La ragione di ciò è che emettere esattamente 1 istruzione SHL / SHR / ecc per implementare l'operatore shift è la cosa migliore che un compilatore C / C ++ ottimizzato può fare quando il contesto non dice nulla su 'x' e 'y'. E, se il compilatore sa per certo che il codice ha un comportamento indefinito, dovrebbe informarne l'utente.

2
Non sono d'accordo. Dovresti scrivere codice portatile. Sia Linux che Windows funzionano su ARM. Concentrarsi su una singola famiglia di CPU è miope. Inoltre, y è una variabile. In effetti, il compilatore non è a conoscenza dei suoi valori di runtime effettivi.
peterSO

@Atom A parte il linguaggio che non fornisce assolutamente alcuna garanzia su ciò che accadrà, è probabile che un comportamento indefinito vari anche su una singola macchina con un singolo compilatore, se ad esempio si modificano le opzioni di compilazione (ad esempio una build ottimizzata). Fare affidamento su di esso in qualsiasi modo è pericolosamente sbagliato IMO.
Paul Hankin

@ Anonimo Sì, ma questa è solo teoria. Potete fornire un esempio concreto in cui la modifica delle opzioni di compilazione porta a comportamenti diversi di <<o >>in C / C ++?

6

<< è il turno di sinistra. >>è lo spostamento a destra di estensione del segno quando l'operando di sinistra è un intero con segno ed è lo spostamento di destra di estensione zero quando l'operando di sinistra è un numero intero senza segno.

Per capire meglio >>pensa

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

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

Quindi, quando applicati a un numero intero senza segno, i bit a sinistra sono riempiti con zero, mentre quando applicati a un intero con segno, i bit a sinistra sono riempiti con il bit più a sinistra (che è 1 quando l'intero con segno è negativo come per 2 complemento).


3

In matematica decimale , quando moltiplichiamo o dividiamo per 10 , applichiamo gli zeri alla fine del numero.

In binario , 2 ha lo stesso effetto. Quindi stiamo aggiungendo uno zero alla fine o rimuovendo l'ultima cifra

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.