Opérateurs Go << et >>

124

Quelqu'un pourrait-il s'il vous plaît m'expliquer l'utilisation de <<et >>dans Go? Je suppose que c'est similaire à d'autres langues.

brianoh
la source

Réponses:

169

La définition super simplifiée (peut-être sur) est juste celle qui <<est utilisée pour «fois 2» et >>pour «divisé par 2» - et le nombre après c'est combien de fois.

Il en n << xva de même pour "n fois 2, x fois". Ety >> z est "y divisé par 2, z fois".

Par exemple, 1 << 5est "1 fois 2, 5 fois" ou 32. Et 32 >> 5est "32 divisé par 2, 5 fois" ou 1.

Toutes les autres réponses donnent la définition la plus technique, mais personne ne l'a vraiment expliquée et j'ai pensé que vous voudriez peut-être cela.

Peter Oram
la source
7
C'est une excellente réponse. Cela l'a vraiment solidifié dans ma tête, merci.
Sam Orozco
2
Voilà comment les réponses devraient être.
Utsav Gupta
103

D'après la spécification à http://golang.org/doc/go_spec.html , il semble qu'au moins avec des entiers, il s'agit d'un décalage binaire. par exemple, le binaire 0b00001000 >> 1 serait 0b00000100 et 0b00001000 << 1 serait 0b00010000.


Go n'accepte apparemment pas la notation 0b pour les entiers binaires. Je l'utilisais juste pour l'exemple. En décimal, 8 >> 1 vaut 4 et 8 << 1 vaut 16. Décaler vers la gauche de un équivaut à une multiplication par 2, et décaler vers la droite de un équivaut à diviser par deux, en supprimant tout reste.

jcomeau_ictx
la source
4
Très bonne réponse. Cela a beaucoup de sens quand je pense que je voyais cela dans le code traitant des puissances de 2 (1 << power = 2 ^ power)
Stephen Smith
6
Je pense que ce serait l'équation complète: (x << n == x * 2 ^ n) (x >> n == x * 2 ^ (- n))
MondayPaper
belle réponse, le décalage binaire m'a semblé gênant au début, mais convertir la valeur en décimal avec des puissances à 2 aide bien à l'obtenir
minhajul
31

Les opérateurs << et >> sont des opérateurs arithmétiques Go .

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

Les opérateurs de décalage décalent l'opérande gauche du nombre de décalages spécifié par l'opérande droit. Ils implémentent des décalages arithmétiques si l'opérande de gauche est un entier signé et des décalages logiques s'il s'agit d'un entier non signé. Le nombre de quarts doit être un entier non signé. Il n'y a pas de limite supérieure sur le nombre d'équipes. Les décalages se comportent comme si l'opérande gauche était décalé n fois de 1 pour un compte de décalage de n. En conséquence, x << 1 est identique à x * 2 et x >> 1 est identique à x / 2 mais tronqué vers l'infini négatif.

peterSO
la source
10

Ce sont essentiellement des opérateurs arithmétiques et c'est la même chose dans d'autres langages, voici un exemple de base PHP, C, Go

ALLER

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

}

Démo 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;
}

Démo 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);
}

Démo PHP

Ils sortiraient tous

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
la source
7

Go's << et >> sont similaires aux décalages (c'est-à-dire: division ou multiplication par une puissance de 2) dans d'autres langages, mais comme Go est un langage plus sûr que C / C ++, il effectue un travail supplémentaire lorsque le nombre de quarts est un nombre .

Les instructions de décalage dans les processeurs x86 ne prennent en compte que 5 bits (6 bits sur les processeurs x86 64 bits) du compte de décalage. Dans des langages comme C / C ++, l'opérateur shift se traduit par une seule instruction CPU.

Le code Go suivant

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

impressions

0
0

alors qu'un programme C / C ++ imprimerait

5
20

la source
3
Pour les opérateurs de décalage C et C ++, "Le comportement n'est pas défini si l'opérande droit est négatif, ou supérieur ou égal à la longueur en bits de l'opérande gauche promu." Les normes C et C ++ ne garantissent pas que les programmes C et C ++ imprimeront 5 et 20.
peterSO
@peterSO: Oui, vous avez raison. Mon point de vue est que chaque standard de langage de programmation doit avoir une implémentation concrète sur une CPU concrète. Dans le contexte d'une seule famille de processeurs (x86-32), le comportement de tous les compilateurs C / C ++ est (on peut s'attendre à ce qu'il soit) le même. La raison en est qu'émettre exactement 1 instruction SHL / SHR / etc pour implémenter l'opérateur shift est la meilleure chose qu'un compilateur d'optimisation C / C ++ puisse faire lorsque le contexte ne lui dit rien sur 'x' et 'y'. Et, si le compilateur sait pertinemment que le code a un comportement indéfini, il doit en informer l'utilisateur.
2
Je ne suis pas d'accord. Vous devriez écrire du code portable. Linux et Windows fonctionnent sur ARM. Se concentrer sur une seule famille de processeurs est à courte vue. De plus, y est une variable. Pour un fait, le compilateur n'a aucune connaissance de ses valeurs d'exécution réelles.
peterSO
@Atom Hormis le langage ne fournissant absolument aucune garantie sur ce qui va se passer, un comportement indéfini est susceptible de varier même sur une seule machine avec un seul compilateur, si par exemple vous changez les options de compilation (par exemple une version optimisée). S'y fier de quelque manière que ce soit est dangereusement faux pour l'OMI.
Paul Hankin
@Anonymous Oui, mais ce n'est que théorie. Pouvez-vous fournir un exemple concret où la modification des options de compilation conduit à un comportement différent de <<ou >>en C / C ++?
6

<<est le décalage à gauche. >>est un décalage vers la droite d'extension de signe lorsque l'opérande de gauche est un entier signé, et est un décalage vers la droite d'extension de zéro lorsque l'opérande de gauche est un entier non signé.

Pour mieux comprendre, >>pensez à

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

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

Ainsi, lorsqu'ils sont appliqués à un entier non signé, les bits à gauche sont remplis de zéro, tandis que lorsqu'ils sont appliqués à un entier signé, les bits à gauche sont remplis avec le bit le plus à gauche (qui est 1 lorsque l'entier signé est négatif selon 2. complément).

Mike Samuel
la source
3

En mathématiques décimales , lorsque nous multiplions ou divisons par 10 , nous effectuons les zéros à la fin du nombre.

En binaire , 2 a le même effet. Nous ajoutons donc un zéro à la fin ou supprimons le dernier chiffre

Robert King
la source