Τα δυαδικά ψηφία αντιστοιχίζονται τελικά άμεσα με τα τρανζίστορ στον CPU ή τη RAM σου, και με το αν το καθένα είναι "ανοιχτό" ή "κλειστό".
Ο χειρισμός χαμηλού επιπέδου, που ανεπίσημα ονομάζεται "bit-twiddling", είναι ιδιαίτερα σημαντικός στις γλώσσες συστημάτων.
Οι γλώσσες υψηλού επιπέδου, όπως η Julia, συνήθως αφαιρούν τις περισσότερες από αυτές τις λεπτομέρειες. Ωστόσο, μια πλήρης σειρά πράξεων σε επίπεδο bit είναι διαθέσιμη στη βασική γλώσσα.
Σημείωση: Για να δεις ευανάγνωστη δυαδική έξοδο στο REPL, σχεδόν όλα τα παρακάτω παραδείγματα πρέπει να τυλιχτούν σε μια συνάρτηση bitstring().
Αυτό αποσπά την προσοχή οπτικά, οπότε οι περισσότερες εμφανίσεις αυτής της συνάρτησης έχουν αφαιρεθεί.
Οι ακέραιοι τύποι, προσημασμένοι ή απρόσημοι, μπορούν να αναπαρασταθούν ως μια συμβολοσειρά από μηδενικά και άσσους.
julia> bitstring(UInt8(5))
"00000101"
Οι ολισθήσεις bit απλώς μετακινούν τα πάντα αριστερά ή δεξιά κατά έναν καθορισμένο αριθμό θέσεων.
Με τους τύπους UInt, κάποια bit πέφτουν από το ένα άκρο και το άλλο άκρο συμπληρώνεται με μηδενικά:
julia> ux::UInt8 = 5
5
julia> bitstring(ux)
"00000101"
julia> ux << 2 # left by 2
"00010100"
julia> ux >> 1 # right by 1
"00000010"
Κάθε ολίσθηση αριστερά διπλασιάζει την τιμή και κάθε ολίσθηση δεξιά την υποδιπλασιάζει (υπόκειται σε περικοπή). Αυτό είναι πιο εμφανές στη δεκαδική αναπαράσταση:
julia> 3 << 2
12
julia> 24 >> 3
3
Μια τέτοια ολίσθηση bit είναι πολύ πιο γρήγορη από την "κανονική" αριθμητική, κάτι που κάνει την τεχνική πολύ δημοφιλή στον προγραμματισμό χαμηλού επιπέδου.
Με τους προσημασμένους ακεραίους, πρέπει να είμαστε λίγο πιο προσεκτικοί.
Οι ολισθήσεις αριστερά είναι σχετικά απλές:
julia> sx = Int8(5)
5
julia> sx # positive integer
"00000101"
julia> sx << 2
"00010100"
julia> -sx # negative integer
"11111011"
julia> -sx << 2
"11101100"
Η ολίσθηση αριστερά θετικών προσημασμένων ακεραίων είναι επομένως ίδια όπως με τους απρόσημους ακεραίους.
Οι αρνητικές τιμές αποθηκεύονται σε μορφή συμπληρώματος ως προς δύο, που σημαίνει ότι το αριστερότερο bit είναι 1. Κανένα πρόβλημα για μια ολίσθηση αριστερά, αλλά όταν ολισθαίνουμε δεξιά, πώς συμπληρώνουμε τα αριστερότερα bit;
julia> sx >> 2 # simple for positive values!
"00000001"
julia> -sx # negative integer
"11111011"
julia> -sx >> 2 # pad with repeated sign bit
"11111110"
julia> -sx >>> 2 # pad with 0
"00111110"
Ο τελεστής >> εκτελεί αριθμητική ολίσθηση, διατηρώντας το bit προσήμου.
Ο τελεστής >>> εκτελεί λογική ολίσθηση, συμπληρώνοντας με μηδενικά σαν ο αριθμός να ήταν απρόσημος.
Είδαμε σε μια προηγούμενη Έννοια ότι οι τελεστές && (και), || (ή) και ! (όχι) χρησιμοποιούνται με Boolean τιμές.
Υπάρχουν αντίστοιχοι τελεστές & (and κατά bit), | (or κατά bit) και ~ (μια περισπωμένη, not κατά bit) για να συγκρίνουν τα bit δύο ακεραίων.
julia> 0b1011 & 0b0010 # bit is 1 in both numbers
"00000010"
julia> 0b1011 | 0b0010 # bit is 1 in at least one number
"00001011"
julia> ~0b1011 # flip all bits
"11110100"
julia> xor(0b1011, 0b0010) # bit is 1 in exactly one number, not both
"00001001"
Εδώ, το xor() είναι το αποκλειστικό ή, χρησιμοποιημένο ως συνάρτηση.
Ο φίλος σου μόλις σου έστειλε ένα μήνυμα με ένα σημαντικό μυστικό. Για να μην μπορούν οι άλλοι να το διαβάσουν εύκολα, το μήνυμα κρυπτογραφήθηκε με μια σειρά χειρισμών bit. Θα χρειαστεί να γράψεις τις συναρτήσεις που θα σε βοηθήσουν να αποκρυπτογραφήσεις το μήνυμα.
Το πρώτο βήμα για να αποκρυπτογραφήσεις το μήνυμα είναι να αναιρέσεις τη μετατόπιση της διαδικασίας κρυπτογράφησης, μετατοπίζοντας τα bit πίσω προς τα δεξιά. Στη συνέχεια της διαδικασίας αποκρυπτογράφησης θα υπάρξουν κι άλλα βήματα που υποθέτουν ότι μπαίνουν μηδενικά από την αριστερή πλευρά.
Υλοποίησε τη συνάρτηση shift_back() που παίρνει μια τιμή και τον αριθμό των θέσεων μετατόπισης και εκτελεί τη μετατόπιση.
shift_back(0b1001, 2) # => 0b0010
Στη συνέχεια, υπάρχουν μερικά bit που πρέπει να οριστούν σε 1.
Υλοποίησε τη συνάρτηση set_bits() που παίρνει μια τιμή και μια μάσκα και επιστρέφει το αποτέλεσμα του ορισμού των bit της τιμής σε 1.
Ένα bit από τη value πρέπει να οριστεί σε 1 όπου το bit της mask είναι επίσης 1.
Όλα τα άλλα bit πρέπει να μείνουν αμετάβλητα.
set_bits(0b0110, 0b0101) # => 0b0111
Κάποια bit αντιστρέφονται κατά την κρυπτογράφηση. Θα χρειαστεί να αντιστραφούν ξανά για να αποκρυπτογραφηθεί το μήνυμα.
Υλοποίησε τη συνάρτηση flip_bits() που παίρνει μια τιμή και τη μάσκα.
Η μάσκα δείχνει ποια bit της τιμής θα αντιστραφούν.
Αν το bit είναι 1 στη mask, το bit αντιστρέφεται στη value.
Όλα τα άλλα bit μένουν αμετάβλητα.
flip_bits(0b1100, 0b0101) # => 0b1001
Τέλος, υπάρχουν και ορισμένα bit που αποκρυπτογραφούνται πάντα σε 0.
Υλοποίησε τη συνάρτηση clear_bits() που παίρνει μια τιμή και μια μάσκα.
Τα bit της value πρέπει να οριστούν σε 0 όπου το bit της μάσκας είναι 1.
Όλα τα άλλα bit πρέπει να μείνουν αμετάβλητα.
clear_bits(0b0110, 0b0101) # => 0b0010
Γράψου στο Exercism για να μάθεις και να κατακτήσεις Julia με 35 έννοιες128 ασκήσεις και πραγματική καθοδήγηση από ανθρώπους, όλα δωρεάν.