ความแตกต่างระหว่าง >>> และ >>


375

ความแตกต่างระหว่าง>>>และ>>ตัวดำเนินการใน Java คืออะไร?


คำตอบ:


408

>> เลขคณิตเปลี่ยนไปทางขวา >>>คือตรรกะที่ถูกต้อง

ในการเปลี่ยนแปลงทางคณิตศาสตร์บิตสัญญาณจะถูกขยายเพื่อรักษาความเซ็นของหมายเลข

ตัวอย่างเช่น: -2 แทนด้วย 8 บิตจะเป็น11111110(เพราะบิตที่สำคัญที่สุดมีน้ำหนักเป็นลบ) เลื่อนไปทางขวาหนึ่งบิตโดยใช้การคำนวณทางคณิตศาสตร์จะให้คุณ11111111หรือ -1 อย่างไรก็ตามการเลื่อนไปทางขวาแบบโลจิคัลไม่ได้สนใจว่าค่าอาจแสดงถึงหมายเลขที่ลงนามแล้ว มันย้ายทุกอย่างไปทางขวาและเติมจากซ้ายด้วย 0s การขยับของเรา -2 01111111ขวาหนึ่งบิตโดยใช้ตรรกะกะจะให้


8
ในขณะที่ฉันเห็นด้วยและชื่นชมว่าการเปลี่ยนแปลงทางคณิตศาสตร์สามารถนำมาใช้เพื่อเพิ่มจำนวนตัวเลขที่ลงนามโดย2^kฉันพบว่ามันแปลกที่นี่คือคำตอบของทุกคน สตริงของบิตไม่ใช่ตัวเลขและ>>สามารถใช้ได้กับสตริงของบิตใด ๆ : มันจะทำสิ่งเดียวกันเสมอโดยไม่คำนึงถึงบทบาทที่สตริงของบิตกำลังเล่นอยู่และไม่ว่ามันจะมีแนวคิดของ 'สัญญาณ' หรือไม่ก็ตาม มันจะโอเคที่จะขยายคำตอบที่ดีของคุณแล้วด้วยการอภิปรายกรณีที่ตัวถูกดำเนินการของคุณจะไม่ถูกตีความว่าเป็นหมายเลขที่ลงนาม? การร้องเรียนของฉันสมเหตุสมผลหรือไม่
Ziggy

11
ทำไมคุณพูดว่าสตริงบิตไม่ใช่ตัวเลข? คุณจะพูดว่าลำดับของตัวเลขทศนิยมไม่ใช่ตัวเลขหรือไม่?
danben

4
@danben การอภิปรายว่าเป็นหรือไม่ตัวเลขก็สมเหตุสมผลถ้าคุณเชื่อมโยงไปยังบริบท หากอินเทอร์เน็ตเป็นเพียงกระแสไฟฟ้าฉันยอมรับว่าสตริงเป็นเพียงตัวเลข
bvdb

1
@danben แต่ที่จริงแล้วผมคิดว่าสิ่ง Ziggy ถูกจริงๆหมายถึง imho () คือว่าอาจจะมีการยกย่องว่าเป็นString char[]เขาไม่ได้พูดว่า a charไม่ใช่ตัวเลข; เขาแค่บอกว่ามันเป็นตัวเลขที่ไม่ได้ลงชื่อ ฉันคิดว่านั่นคือสิ่งที่เขาหายไป
bvdb

5
@ Ziggy นั้นถูกต้อง: ไม่ใช่ทุก ๆ สตริงของตัวเลขคือตัวเลขและไม่ใช่ทุก ๆ ลำดับของเลขทศนิยมคือตัวเลข ตัวอย่างเช่น: หมายเลขโทรศัพท์รหัสโพสต์ (ในหลายประเทศ) เป็นต้นเป็นสตริงของตัวเลขทศนิยม แต่มันก็ไม่สมเหตุสมผลที่จะเพิ่มลบหรือทวีคูณพวกเขาจึงไม่ใช่ตัวเลขจริงๆ มันเกิดขึ้นเป็นสตริงตัวเลขทศนิยม แต่ควรถือว่าเป็นสตริงของอักขระ (รหัสไปรษณีย์ในแคนาดาและสหราชอาณาจักรมีตัวอักษรและตัวเลข)
jcsahnwaldt พูดว่า GoFundMonica

102

>>>ไม่มีการเปลี่ยนแปลง มันจะแทรก 0 >>ลงนามและจะขยายบิตสัญญาณ

JLS 15.19 Shift Operators

ผู้ประกอบการเปลี่ยนแปลงรวมถึงการเปลี่ยนแปลงทางด้านซ้าย<<ลงนามกะขวา>>, >>>และการเปลี่ยนแปลงทางด้านขวาได้รับการรับรอง

คุณค่าของ n>>sเป็นnขวาขยับsตำแหน่งบิตที่มีการลงชื่อเข้าใช้นามสกุล

ค่าของn>>>sถูกnเลื่อนไปทางขวาsตำแหน่งบิตที่มีศูนย์ขยาย

    System.out.println(Integer.toBinaryString(-1));
    // prints "11111111111111111111111111111111"
    System.out.println(Integer.toBinaryString(-1 >> 16));
    // prints "11111111111111111111111111111111"
    System.out.println(Integer.toBinaryString(-1 >>> 16));
    // prints "1111111111111111"

เพื่อให้สิ่งต่าง ๆ ชัดเจนยิ่งขึ้นการเพิ่มคู่ที่เป็นบวก

System.out.println(Integer.toBinaryString(121));
// prints "1111001"
System.out.println(Integer.toBinaryString(121 >> 1));
// prints "111100"
System.out.println(Integer.toBinaryString(121 >>> 1));
// prints "111100"

เนื่องจากเป็นบวกทั้งกะที่ลงนามและไม่ได้ลงชื่อจะเพิ่ม 0 เหลือบิตมากที่สุด

คำถามที่เกี่ยวข้อง


หากไม่มีตัวอย่างของคุณฉันจะไม่เข้าใจ
mr5

47

พวกเขาเป็นทั้งกะขวา แต่>>>เป็นunsigned

จากเอกสาร :

ตัวดำเนินการเลื่อนด้านขวาที่ไม่ได้ลงนาม ">>>" จะเลื่อนศูนย์เป็นตำแหน่งซ้ายสุดในขณะที่ตำแหน่งซ้ายสุดหลัง ">>" ขึ้นอยู่กับส่วนขยายของสัญญาณ


12
คุณช่วยอธิบายด้วยตัวอย่างได้
ไหม

1
ฉันคิดว่าคุณควรยกตัวอย่าง
byxor

ฉันคิดว่า>>>มันไม่ได้ลงชื่อ แต่ทำไม7>>32=7? ฉันวิ่งห่วงที่ไม่เปลี่ยนแปลงหนึ่งในเวลาและเห็นว่าหลังจากที่มีการเปลี่ยนแปลงก็จะกลับมา32 7วิธีเดียวที่สิ่งนี้ทำให้เข้าใจได้คือสำหรับแต่ละหมายเลขที่เลื่อนออกไปมันเข้าสู่ "วงนอก" หลังจาก32เปลี่ยนไปมันก็กลับมาที่ตำแหน่งเดิม แต่ก็เห็นได้ชัดว่ายังไม่สมเหตุสมผล เกิดอะไรขึ้น?
Ian Limarta

@IanLimarta มันไม่ได้เหรอ? ฉันเพิ่งได้รับ 0. ( for (int i = 7 << 1, j = 0; j < 32; j++) System.out.println(Integer.toString(i >>= 1, 2));) ถ้าคุณหมายถึงว่าทำไม>>32ตัวเองกลับค่าเดิมที่เห็นนี้
Moira

ฉันขอโทษ. ฉันหมายความว่าทำไม '7 >>> 32 = 7'
Ian Limarta

40

ตรรกะการเลื่อนขวา ( v >>> n) ส่งคืนค่าที่บิตในvถูกเลื่อนไปทางขวาโดยnตำแหน่งบิตและ 0 ถูกเลื่อนเข้ามาจากด้านซ้าย พิจารณาเปลี่ยนค่า 8 บิตเขียนในไบนารี:

01111111 >>> 2 = 00011111
10000000 >>> 2 = 00100000

ถ้าเราตีความบิตเป็นจำนวนเต็มไม่เป็นลบเชิงลบการเลื่อนขวาแบบลอจิคัลมีผลในการหารจำนวนด้วยกำลังที่สอดคล้องกันของ 2 อย่างไรก็ตามถ้าตัวเลขอยู่ในการแทนสองส่วนเติมเต็มการเลื่อนขวาเชิงตรรกะไม่ถูกต้องหารจำนวนลบ . ตัวอย่างเช่นการเลื่อนขวาที่สองด้านบนเลื่อน 128 ถึง 32 เมื่อบิตถูกตีความว่าเป็นตัวเลขที่ไม่ได้ลงนาม แต่มันจะเลื่อน -128 เป็น 32 เมื่อตามปกติใน Java บิตจะถูกตีความในส่วนเติมเต็มของสอง

ดังนั้นหากคุณขยับเพื่อหารด้วยกำลังสองคุณต้องการการคำนวณทางขวา ( v >> n) มันส่งกลับค่าที่บิตในvได้ถูกเลื่อนไปทางขวาโดยnตำแหน่งบิตและสำเนาของบิตซ้ายสุดของ vจะถูกย้ายจากด้านซ้าย:

01111111 >> 2 = 00011111
10000000 >> 2 = 11100000

เมื่อบิตเป็นตัวเลขในการเป็นตัวแทนสองส่วนการเลื่อนขวาของเลขคณิตมีผลกระทบจากการหารด้วยกำลังสอง สิ่งนี้ใช้งานได้เพราะบิตทางซ้ายสุดคือบิตเครื่องหมาย การหารด้วยกำลังสองจะต้องรักษาเครื่องหมายเหมือนเดิม


38

>>>จะใส่ 0 ในบิตซ้ายสุดเสมอในขณะที่>>จะใส่ 1 หรือ 0 ขึ้นอยู่กับว่าสัญญาณของมันคืออะไร


10

อ่านเพิ่มเติมเกี่ยวกับผู้ประกอบการ Bitwise และ Bit Shift

>>      Signed right shift
>>>     Unsigned right shift

รูปแบบบิตถูกกำหนดโดยตัวถูกดำเนินการทางซ้ายและจำนวนตำแหน่งที่จะเลื่อนโดยตัวถูกดำเนินการทางขวา ตัวดำเนินการเลื่อนด้านขวาที่ไม่ได้ลงนาม>>> จะเลื่อนศูนย์ให้อยู่ในตำแหน่งซ้ายสุด ,

ในขณะที่ตำแหน่งซ้ายสุดหลังจาก >>ขึ้นอยู่กับส่วนขยายสัญญาณ

คำง่าย ๆ>>>จะเลื่อนศูนย์ไปที่ตำแหน่งซ้ายสุดเสมอในขณะที่>>การเลื่อนขึ้นอยู่กับเครื่องหมายของตัวเลขเช่น 1 สำหรับจำนวนลบและ 0 สำหรับจำนวนบวก


ตัวอย่างเช่นลองลบจำนวนบวก

int c = -153;
System.out.printf("%32s%n",Integer.toBinaryString(c >>= 2));
System.out.printf("%32s%n",Integer.toBinaryString(c <<= 2));
System.out.printf("%32s%n",Integer.toBinaryString(c >>>= 2));
System.out.println(Integer.toBinaryString(c <<= 2));

System.out.println();

c = 153;
System.out.printf("%32s%n",Integer.toBinaryString(c >>= 2));
System.out.printf("%32s%n",Integer.toBinaryString(c <<= 2));
System.out.printf("%32s%n",Integer.toBinaryString(c >>>= 2));
System.out.printf("%32s%n",Integer.toBinaryString(c <<= 2));

เอาท์พุท:

11111111111111111111111111011001
11111111111111111111111101100100
  111111111111111111111111011001
11111111111111111111111101100100

                          100110
                        10011000
                          100110
                        10011000

ขอบคุณ เพียงแค่ต้องการที่จะเพิ่มความคิดเห็นเพื่ออ้างอิงตัวแทนบิตสำหรับInteger.MAX_VALUE, Integer.MIN_VALUE, -1, 0, 1 เช่น: System.out.println(Integer.MAX_VALUE + ": " + String.format("%32s", Integer.toBinaryString(Integer.MAX_VALUE)).replace(' ', '0')); Integer.MAX_VALUE : 01111111111111111111111111111111; Integer.MIN_VALUE : 10000000000000000000000000000000; -1 : 11111111111111111111111111111111; 0 : 00000000000000000000000000000000; 1 : 00000000000000000000000000000001
Andy Dong

6

ตัวดำเนินการเลื่อนตรรกะด้านขวา ( >>> N) เลื่อนบิตไปทางขวาตามตำแหน่ง N โดยละทิ้งเครื่องหมายบิตและเติมบิตที่เหลือมากที่สุด N ด้วย 0 ตัวอย่างเช่น:

-1 (in 32-bit): 11111111111111111111111111111111

หลังจากการ>>> 1ดำเนินการกลายเป็น:

2147483647: 01111111111111111111111111111111

ตัวดำเนินการทางคณิตศาสตร์ shift shift ที่ถูกต้อง ( >> N) ยังเลื่อนบิตไปทางขวาด้วยตำแหน่ง N แต่เก็บบิตสัญญาณไว้และวางบิต N ซ้ายสุดด้วย 1's ตัวอย่างเช่น:

-2 (in 32-bit): 11111111111111111111111111111110

หลังจากการ>> 1ดำเนินการกลายเป็น:

-1: 11111111111111111111111111111111
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.