2015-02-10 3 views
16

Недавно я прочитал спецификацию golang и столкнулся с некоторыми интересными операторами:Разница между некоторыми операторами «|», «^», «&», «& ^». Golang

& bitwise AND   integers 
| bitwise OR    integers 
^ bitwise XOR   integers 
&^ bit clear (AND NOT) integers 

Я пытался играть с ним, но только один я понял, что «|» добавлять целые числа и оператор «+» дополнительно работать с поплавками, строками и т. д.

Что они используются на практике? Может ли кто-нибудь дать некоторое объяснение этим 4 операторам выше?

+2

Возьмите книгу, подобную «Коду» Петцольда, чтобы получить базовое представление о двоичном представлении и основах вычислений. –

ответ

30

Побитовые операторы вступают в игру, когда вам нужно работать с байтовыми или битовыми данными.

Здесь я перечисляю несколько примеров использования битовых операций с примерами кода (в произвольном порядке):


1. Они являются общими и частью многих алгоритмов в криптографии и хэш функции (например, MD5).

2. Они также часто используются, если вы хотите «сохранить» пространство, и вы пакет несколько «BOOL» переменные в один int, например, присвоить бит каждой переменной BOOL. Вы должны использовать побитовые операторы, чтобы иметь возможность индивидуально изменять/читать биты.

Например упаковка 8 бит/Bools в один int:

flags := 0x00 // All flags are 0 
flags |= 0x02 // Turn the 2nd bit to 1 (leaving rest unchanged) 
flags |= 0xff // Turn 8 bits (0..7) to 1 
flags &= 0xfe // Set the lowest bit to 0 (leaving rest unchanged) 

istrue := flags&0x04 != 0 // Test if 3rd bit is 1 

3. Другая область сжатия данных, где вы хотите, чтобы получить максимальную отдачу от byte и использовать все биты в хранить/извлекать некоторую информацию (немного - базовая единица информации в вычислительной и цифровой связи).

4. Аналогично сжатию, но не совсем то же: bitstreams. Он также используется для экономии места в потоке данных, не отправляя полные байты, а скорее поля с произвольной длиной бит.

Я написал и опубликовал высоко оптимизированный пакет Reader и Writer на уровне бит, открытый здесь: github.com/icza/bitio. Вы увидите широкое использование всех видов бит-операций в своих источниках.

5. Другое практическое использование: тестирования определенных свойств (целое число) чисел. Зная двоичное представление целочисленных чисел (Two's complement), в их двоичном представлении есть определенные характеристики чисел. Например целое число (в 2 с дополнением) является даже (можно разделить на 2), если младший бит равен 0:

func isEven(i int) bool { 
    return i&0x01 == 0 
} 

Тестируя биты целого числа вы можете сказать, если это сила of 2. Например, если положительное число содержит только один бит 1, тогда это сила 2 (например,2 = 0x02 = 00000010b, 16 = 0x10 = 00010000, но, например, 17 = 0x11 = 00010001 нет мощности 2).

6.Многие процедуры кодирования/декодирования также используют битовые операции. Наиболее тривиальным является UTF-8 encoding, который использует кодировку переменной длины для представления кодовых точек Unicode (rune в Go) в качестве последовательностей байтов.
Простым вариантом кодирования с переменной длиной слова может быть использование наивысшего бита байта (8-го или 7-го, если индексируется 0), чтобы сигнализировать, требуется ли больше байтов для декодирования числа, а остальные 7 бит всегда являются «полезные» данные. Вы можете проверить старший бит и «отдельные» 7 полезных битов, как это:

b := readOneByte() 
usefulBits := b & 0x7f 
hasMoreBytes := b & 0x80 != 0 

Прибыль использования такого кодирования переменной длины, что даже если вы используете uint64 типа в Go, которая 8 байт памяти , небольшие числа все еще могут быть представлены с использованием меньшего количества байтов (номера в диапазоне 0..127 требуют только 1 байт!). Если образцы, которые вы хотите сохранить или передать, имеют много небольших значений, это само по себе может сжать данные до 1/8-го = 12,5%. Нижняя сторона состоит в том, что большие числа (которые имеют биты даже в самом высоком байте) будут использовать более 8 байтов. Стоит ли это того, что это зависит от эвристики образцов.

X.И этот список можно продолжить ...


Можно ли жить, не зная,/используя битовые операторы Go (и во многих других языках программирования)? Ответ: Да. Но если вы их знаете, иногда они могут сделать вашу жизнь проще и ваши программы более эффективными.

Если вы хотите узнать больше по этой теме, прочитайте статью Википедии: Bitwise operation и google термин «Побитовое руководство по операциям», есть много хороших статей.

+0

Спасибо! Действительно хороший ответ. Не могли бы вы предложить книгу, в которой объясняются некоторые основы программирования «низкого уровня» для новичков, подобных мне? (без углубления в слишком технические и математические термины) –

+1

@TimurFayzrakhmanov Просто google it (термин «побитовые операторы tutorial» _), в Интернете есть много хороших обучающих программ. Большинство из них являются языковыми, но более или менее они применимы ко всем языкам программирования. Вот хороший, найденный за 1 минуту googling: [Понимание побитовых операторов] (http://code.tutsplus.com/articles/understanding-bitwise-operators--active-11301). Также читайте статью в википедии: [Побитовая операция] (http://en.wikipedia.org/wiki/Bitwise_operation) – icza

+0

получил это! Еще раз спасибо!) –

13

За то, что они технически делать проверить комментарии в этом

package main 

import "fmt" 

func main() { 
    // Use bitwise OR | to get the bits that are in 1 OR 2 
    // 1  = 00000001 
    // 2  = 00000010 
    // 1 | 2 = 00000011 = 3 
    fmt.Println(1 | 2) 

    // Use bitwise OR | to get the bits that are in 1 OR 5 
    // 1  = 00000001 
    // 5  = 00000101 
    // 1 | 5 = 00000101 = 5 
    fmt.Println(1 | 5) 

    // Use bitwise XOR^to get the bits that are in 3 OR 6 BUT NOT BOTH 
    // 3  = 00000011 
    // 6  = 00000110 
    // 3^6 = 00000101 = 5 
    fmt.Println(3^6) 

    // Use bitwise AND & to get the bits that are in 3 AND 6 
    // 3  = 00000011 
    // 6  = 00000110 
    // 3 & 6 = 00000010 = 2 
    fmt.Println(3 & 6) 

    // Use bit clear AND NOT &^ to get the bits that are in 3 AND NOT 6 (order matters) 
    // 3  = 00000011 
    // 6  = 00000110 
    // 3 &^ 6 = 00000001 = 1 
    fmt.Println(3 &^ 6) 
} 

View it on the playground

Пожалуйста, обратите внимание, что я дал два примера |, чтобы показать, что это на самом деле не дополнение, как 1 + 5.

Что касается практического использования, я уверен, что некоторые другие могут комментировать примеры из других источников, но одно из распространенных способов - создать битовую маску флагов для чего-то вроде системы разрешений.