Đi tới các toán tử << và >>


124

Ai đó có thể vui lòng giải thích cho tôi cách sử dụng <<>>trong Go không? Tôi đoán nó tương tự với một số ngôn ngữ khác.

Câu trả lời:


169

Định nghĩa đơn giản hóa siêu (có thể hơn) chỉ <<được sử dụng cho "lần 2" và >>"chia cho 2" - và số sau nó là bao nhiêu lần.

Như vậy n << xlà "n lần 2, x lần". Và y >> zlà "y chia cho 2, z lần".

Ví dụ: 1 << 5là "1 nhân 2, 5 lần" hoặc 32. Và 32 >> 5là "32 chia cho 2, 5 lần" hoặc 1.

Tất cả các câu trả lời khác cung cấp định nghĩa kỹ thuật hơn, nhưng không ai đưa ra nó một cách thực sự thẳng thắn và tôi nghĩ bạn có thể muốn điều đó.


7
Đây là một câu trả lời tuyệt vời. Điều này thực sự củng cố nó trong đầu tôi, cảm ơn.
Sam Orozco

2
Đây là cách câu trả lời nên được.
Utsav Gupta

103

Từ thông số kỹ thuật tại http://golang.org/doc/go_spec.html , có vẻ như ít nhất với số nguyên, đó là một dịch chuyển nhị phân. ví dụ: nhị phân 0b00001000 >> 1 sẽ là 0b00000100 và 0b00001000 << 1 sẽ là 0b00010000.


Go dường như không chấp nhận ký hiệu 0b cho số nguyên nhị phân. Tôi chỉ sử dụng nó để làm ví dụ. Trong hệ thập phân, 8 >> 1 là 4, và 8 << 1 là 16. Chuyển sang trái bởi một giống như phép nhân với 2 và chuyển sang phải với một cũng giống như chia cho hai, loại bỏ bất kỳ phần dư nào.


4
Câu trả lời chính xác. Nó làm cho rất nhiều ý nghĩa khi tôi nghĩ rằng tôi đã nhìn thấy điều này trong mã giao dịch với lũy thừa của 2 (1 << điện = 2 ^ điện)
Stephen Smith

6
Tôi nghĩ đây sẽ là phương trình đầy đủ: (x << n == x * 2 ^ n) (x >> n == x * 2 ^ (- n))
MondayPaper 19/02/15

thoải mái trả lời, tôi chuyển nhị phân có vẻ rắc rối lúc đầu nhưng chuyển đổi giá trị thành số thập phân với quyền hạn đến 2 giúp tốt để có được nó
minhajul

31

Các toán tử << và >> là các toán tử số học Go .

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

Các toán tử shift dịch chuyển toán hạng bên trái bằng số dịch chuyển được chỉ định bởi toán hạng bên phải. Chúng thực hiện dịch chuyển số học nếu toán hạng bên trái là một số nguyên có dấu và dịch chuyển logic nếu nó là một số nguyên không dấu. Số lượng ca phải là một số nguyên không dấu. Không có giới hạn trên về số ca làm việc. Dịch chuyển hoạt động như thể toán hạng bên trái được dịch n lần 1 với số lần dịch chuyển là n. Kết quả là x << 1 giống với x * 2 và x >> 1 giống với x / 2 nhưng bị cắt bớt về phía âm vô cùng.


10

Về cơ bản chúng là các toán tử số học và nó giống nhau trong các ngôn ngữ khác ở đây là ví dụ cơ bản về PHP, C, Go

ĐI

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

Bản trình diễn PHP

Tất cả họ sẽ xuất

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

<< và >> của Go tương tự như shift (nghĩa là: chia hoặc nhân với lũy thừa 2) trong các ngôn ngữ khác, nhưng vì Go là ngôn ngữ an toàn hơn C / C ++ nên nó thực hiện một số công việc bổ sung khi số shift là một số .

Lệnh shift trong CPU x86 chỉ xem xét 5 bit (6 bit trên CPU x86 64 bit) của số lượng shift. Trong các ngôn ngữ như C / C ++, toán tử shift sẽ chuyển thành một lệnh CPU duy nhất.

Mã Go sau

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

bản in

0
0

trong khi một chương trình C / C ++ sẽ in

5
20

3
Đối với các toán tử dịch chuyển C và C ++, "Hành vi không được xác định nếu toán hạng bên phải là số âm hoặc lớn hơn hoặc bằng độ dài tính bằng bit của toán hạng bên trái được thăng cấp." Các tiêu chuẩn C ++ C và không đảm bảo rằng C và C ++ chương trình sẽ in 5 và 20.
peterSO

@peterSO: Vâng, bạn nói đúng. Quan điểm của tôi là mỗi tiêu chuẩn ngôn ngữ lập trình phải có một triển khai cụ thể trên một CPU cụ thể. Trong ngữ cảnh của một họ CPU (x86-32), hành vi của tất cả các trình biên dịch C / C ++ là (có thể được mong đợi là) giống nhau. Lý do cho điều này là việc phát ra chính xác 1 lệnh SHL / SHR / etc để triển khai toán tử shift là điều tốt nhất mà trình biên dịch C / C ++ tối ưu hóa có thể làm khi ngữ cảnh không cho nó biết bất cứ điều gì về 'x' và 'y'. Và, nếu trình biên dịch biết thực tế rằng mã có hành vi không xác định, nó sẽ thông báo cho người dùng về điều đó.

2
Tôi không đồng ý. Bạn nên viết mã di động. Cả Linux và Windows đều chạy trên ARM. Tập trung vào một họ CPU là thiển cận. Ngoài ra, y là một biến. Thực tế là, trình biên dịch không có kiến ​​thức về các giá trị thời gian chạy thực tế của nó.
peterSO

@Atom Ngoài ngôn ngữ cung cấp hoàn toàn không đảm bảo về những gì sẽ xảy ra, hành vi không xác định có thể thay đổi ngay cả trên một máy với một trình biên dịch, ví dụ: nếu bạn thay đổi các tùy chọn biên dịch (ví dụ: một bản dựng được tối ưu hóa). Dựa vào bất kỳ cách nào đều là sai lầm nguy hiểm IMO.
Paul Hankin

@Anonymous Có, nhưng đó chỉ là lý thuyết. Bạn có thể cung cấp một ví dụ cụ thể nơi việc thay đổi các tùy chọn biên dịch dẫn đến hành vi khác nhau của <<hoặc >>trong C / C ++ không?

6

<<là dịch trái. >>là dịch chuyển sang phải mở rộng dấu khi toán hạng bên trái là số nguyên có dấu và là dịch chuyển sang phải mở rộng bằng 0 khi toán hạng bên trái là số nguyên không dấu.

Để hiểu rõ hơn, >>hãy nghĩ về

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

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

Vì vậy, khi áp dụng cho một số nguyên không dấu, các bit ở bên trái được điền bằng 0, trong khi khi áp dụng cho một số nguyên có dấu, các bit ở bên trái được lấp đầy bằng bit ngoài cùng bên trái (là 1 khi số nguyên có dấu là âm trên 2 của bổ sung).


3

Trong toán học thập phân , khi chúng ta nhân hoặc chia cho 10 , chúng ta sẽ tính các số không ở cuối số.

Trong hệ nhị phân , 2 có cùng tác dụng. Vì vậy, chúng tôi đang thêm một số 0 vào cuối hoặc xóa chữ số cuối cùng

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.