Τι είναι οι τελεστές bitwise shift (bit-shift) και πώς λειτουργούν;

Προσπαθώ να μάθω τη C στον ελεύθερο χρόνο μου και άλλες γλώσσες (C#, Java, κ.λπ.) έχουν την ίδια έννοια (και συχνά τους ίδιους τελεστές) ...

Αυτό που αναρωτιέμαι είναι, σε ένα βασικό επίπεδο, τι κάνει η μετατόπιση bit (<<, >>, >>>>), ποια προβλήματα μπορεί να βοηθήσει να λυθούν, και ποιες δυσκολίες παραμονεύουν πίσω από τη στροφή; Με άλλα λόγια, ένας οδηγός για απόλυτους αρχάριους για το bit shifting σε όλη του την καλοσύνη.

Λύση

Οι τελεστές μετατόπισης bit κάνουν ακριβώς αυτό που υποδηλώνει το όνομά τους. Μετατοπίζουν τα bits. Ακολουθεί μια σύντομη (ή όχι και τόσο σύντομη) εισαγωγή στους διάφορους τελεστές μετατόπισης.

Οι τελεστές

  • >> είναι ο αριθμητικός (ή προσημασμένος) τελεστής δεξιάς μετατόπισης.
  • >>>> είναι ο λογικός (ή μη προσημασμένος) τελεστής δεξιάς μετατόπισης.
  • Ο `>)

Η αριθμητική δεξιά μετατόπιση είναι ακριβώς όπως η λογική δεξιά μετατόπιση, μόνο που αντί να γεμίζει με μηδέν, γεμίζει με το πιο σημαντικό bit. Αυτό συμβαίνει επειδή το πιο σημαντικό bit είναι το sign bit, ή το bit που διακρίνει τους θετικούς και τους αρνητικούς αριθμούς. Με το γέμισμα με το πιο σημαντικό bit, η αριθμητική δεξιά μετατόπιση διατηρεί το πρόσημο.

Για παράδειγμα, αν ερμηνεύσουμε αυτό το μοτίβο bit ως αρνητικό αριθμό:

10000000 00000000 00000000 01100000

έχουμε τον αριθμό -2.147.483.552. Αν τον μετατοπίσουμε προς τα δεξιά κατά 4 θέσεις με την αριθμητική μετατόπιση (-2,147,483,552 >> 4) θα μας δώσει:

11111000 00000000 00000000 00000110

ή τον αριθμό -134.217.722.

Βλέπουμε λοιπόν ότι διατηρήσαμε το πρόσημο των αρνητικών μας αριθμών χρησιμοποιώντας την αριθμητική δεξιά μετατόπιση και όχι τη λογική δεξιά μετατόπιση. Και για άλλη μια φορά, βλέπουμε ότι εκτελούμε διαίρεση με δυνάμεις του 2.

Σχόλια (22)

Ας πούμε ότι έχουμε ένα μόνο byte:

0110110

Εφαρμόζοντας μια απλή αριστερή μετατόπιση bit μας δίνει:

1101100

Το αριστερότερο μηδέν μετατοπίστηκε από το byte και ένα νέο μηδέν προστέθηκε στο δεξί άκρο του byte.

Τα bits δεν ανατρέπονται, απορρίπτονται. Αυτό σημαίνει ότι αν μετατοπίσετε αριστερά το 1101100 και στη συνέχεια το μετατοπίσετε δεξιά, δεν θα λάβετε πίσω το ίδιο αποτέλεσμα.

Η αριστερή μετατόπιση κατά N ισοδυναμεί με πολλαπλασιασμό με 2N.

Η μετατόπιση προς τα δεξιά κατά N είναι (αν χρησιμοποιείτε [ones' complement][1]) ισοδύναμη με τη διαίρεση με 2N και στρογγυλοποίηση στο μηδέν.

Η μετατόπιση bit μπορεί να χρησιμοποιηθεί για εξωφρενικά γρήγορο πολλαπλασιασμό και διαίρεση, με την προϋπόθεση ότι εργάζεστε με μια δύναμη του 2. Σχεδόν όλες οι ρουτίνες γραφικών χαμηλού επιπέδου χρησιμοποιούν τη μετατόπιση bit.

Για παράδειγμα, πολύ παλιά, χρησιμοποιούσαμε τη λειτουργία 13h (320x200 256 χρώματα) για παιχνίδια. Στη λειτουργία 13h, η μνήμη βίντεο ήταν τοποθετημένη διαδοχικά ανά εικονοστοιχείο. Αυτό σήμαινε ότι για να υπολογίσετε τη θέση για ένα εικονοστοιχείο, θα χρησιμοποιούσατε τα ακόλουθα μαθηματικά:

memoryOffset = (row * 320) + column

Τώρα, εκείνη την εποχή, η ταχύτητα ήταν κρίσιμη, οπότε χρησιμοποιούσαμε bitshifts για να κάνουμε αυτή τη λειτουργία.

Ωστόσο, το 320 δεν είναι δύναμη του δύο, οπότε για να το παρακάμψουμε αυτό πρέπει να βρούμε ποια είναι η δύναμη του δύο που προστιθέμενη μαζί κάνει 320:

(row * 320) = (row * 256) + (row * 64)

Τώρα μπορούμε να το μετατρέψουμε σε αριστερές μετατοπίσεις:


(row * 320) = (row 
Σχόλια (6)

Ένα πρόβλημα είναι ότι τα ακόλουθα εξαρτώνται από την εφαρμογή (σύμφωνα με το πρότυπο ANSI):

char x = -1;
x >> 1;

Το x μπορεί τώρα να είναι 127 (0111111111) ή ακόμα -1 (1111111111).

Στην πράξη, είναι συνήθως το τελευταίο.

Σχόλια (3)