Go语言的<<和>>运算符

209

请问有人能够解释一下在Go语言中使用的<<>>的用法吗?我猜它和其他一些编程语言相似。

10个回答

365

超级(可能是过度)简化的定义是,<<表示“乘以2”,>>表示“除以2”,而其后的数字表示使用的次数。

所以,n << x是“n乘以2,x次”,而y>>z则是“y除以2,z次”。

例如,1 << 5表示“1乘以2,5次”,即32。而32 >> 5表示“32除以2,5次”,即1。


21
这是一个很棒的回答。它真正巩固了我的理解,谢谢。 - Sam Orozco
14
这就是答案应该呈现的方式。 - Utsav Gupta
9
如果您解释一下“2,x次方”是什么意思,这可能会更加清晰。在叙述上,例子听起来像是“把5个2相加”,这将得到10,而不是32。请注意,要使内容更加通俗易懂但不改变原有意思。 - schemanic
1
3 << 0 怎么样? - Allan Guwatudde
1
根据schemanic的评论,@AllanGuwatudde,正确答案应该是3 << 0,意思是“3乘以2的0次方”,答案为3,因为2的0次方等于1。 - Alaa Radwan
显示剩余4条评论

136

http://golang.org/doc/go_spec.html的规范来看,至少对于整数而言,这是一个二进制位移。例如,二进制 0b00001000 >> 1 将变为 0b00000100,而 0b00001000 << 1 则将变为 0b00010000。


Go 显然不接受二进制整数的 0b 表示法。我只是用它作为示例。在十进制中,8 >> 1 是 4,8 << 1 是 16。向左移动一位相当于乘以 2,向右移动一位相当于除以 2,舍去任何余数。


5
好的回答。当我看到处理2的幂次方的代码时(1 << power = 2^power),它让我感到很有道理。 - Stephen Smith
10
我认为这将是完整的方程式:(x << n == x2^n) (x >> n == x2^(-n)) 其中 "<< n" 表示将 x 左移 n 位,">> n" 表示将 x 右移 n 位,"==" 表示两边相等,"*" 表示乘法,"^" 表示幂运算。 - MondayPaper
不错的答案,二进制移位一开始似乎很麻烦,但是将值转换为2的幂的十进制数可以很好地解决它。 - MinhajulAnwar

35

<< 和 >> 运算符是Go算术运算符

<<   left shift             integer << unsigned integer
>>   right shift            integer >> unsigned integer
移位运算符将左操作数按右操作数指定的移位次数进行移位。如果左操作数是有符号整数,则它们实现算术移位;如果左操作数是无符号整数,则它们实现逻辑移位。移位计数必须是无符号整数,移位计数没有上限。移位的行为就好像左操作数按1进行n次移位一样。因此,x << 1相当于x乘以2,x >> 1相当于x除以2但向负无穷截断。

22

这些基本上是 算术运算符,在其他语言中也是相同的,这里有一个基本的 PHP、C、Go 示例。

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

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 

13

n << x = n * 2^x 示例:3 << 5 = 3 * 2^5 = 96

y >> z = y / 2^z 示例:512 >> 4 = 512 / 2^4 = 32


1
目前你的回答不够清晰,请编辑并添加更多细节,以帮助其他人理解它如何回答问题。你可以在帮助中心找到有关如何编写好答案的更多信息。 - Community

8
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

4
对于 C 和 C++ 的位移运算符,“如果右操作数为负数或大于等于所提升的左操作数的位数长度,则行为未定义。” C 和 C++ 标准不能保证 C 和 C++ 程序将输出 5 和 20。 - peterSO
@peterSO:是的,你说得对。我的观点是每种编程语言标准都必须在具体的CPU上有一个具体的实现。在单个CPU系列(x86-32)的情况下,所有C/C++编译器的行为(可以预期)都是相同的。原因是当上下文没有告诉编译器关于“x”和“y”的任何信息时,发出恰好1个SHL/SHR等指令来实现移位运算符是优化的C/C++编译器能做的最好的事情。而且,如果编译器确切地知道代码存在未定义的行为,它应该通知用户。 - user811773
2
我不同意。你应该编写可移植的代码。Linux和Windows都可以在ARM上运行。专注于单个CPU系列是短视的。此外,y是一个变量。事实上,编译器无法知道它的实际运行时值。 - peterSO
除了语言本身完全没有提供任何关于会发生什么的保证之外,未定义行为甚至在单个机器上使用单个编译器时也可能有所不同,例如如果您更改编译选项(例如优化构建)。 在我看来,以任何方式依赖它都是非常危险的错误。 - Paul Hankin
@Anonymous 是的,但那只是理论。你能提供一个具体的例子吗,证明在C/C++中改变编译选项会导致<<>>的行为不同? - user811773

8

<< 表示左移。当左操作数是有符号整数时,>> 表示符号扩展右移;当左操作数是无符号整数时,表示零扩展右移。

为了更好地理解 >>,可以想象

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表示负数)。


7
在十进制数学中,当我们乘以或除以10时,会影响数字末尾的零。
在二进制中,数字2具有相同的效果。因此,我们要么在末尾添加一个零,要么删除最后一位数字。

2
“<<”是位左移运算符,它将相应整数的位向左移动...移位后最右边的位为“0”。
例如:
在gcc中,我们有4字节的整数,即32位。
像3的二进制表示为
00000000 00000000 00000000 00000011
3<<1会得到
00000000 00000000 00000000 00000110,即6。
一般地,1<
在gcc中,
1<<20会给出2^20,即1048576,
但在tcc中,它会给你0作为结果,因为tcc中的整数是2个字节。
简单来说,在golang中,我们可以这样理解:
“n << x”是“n乘以2,x次”的意思。而“y >> z”是“y除以2,z次”的意思。
“n << x = n * 2^x 例如:3<<5 = 3 * 2^5 = 96”
“y >> z = y / 2^z 例如:512 >> 4 = 512 / 2^4 = 32”

0

这些是右位运算符和左位运算符


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接