2009-08-08 1 views
10

Большинство констант я вижу в других коде являются степенями 2, т.е.Почему мы всегда объявляем константы силой 2?

#define SIZE 256 

или

public static final int SIZE = 2048; 

Есть ли конкретная причина, почему мы делаем, что вместо того, чтобы есть

#define SIZE 257 

?

+2

Я не думаю, что на этот вопрос можно ответить, не зная, для чего используется константа. Целью константы является то, что определяет, какие значения может принять константа. –

+0

Примером может быть размер массива int. – 2009-08-08 17:09:08

+1

Я думаю, вы думаете, что мы используем силы на 2 больше, чем они используются на самом деле. Люди будут использовать массив из 100 ints, такой же, как массив из 256. Битмаскирование является основной причиной для полномочий 2 и не применяется к размерам массивов. –

ответ

29

Полномочия 2 удобны, потому что они хорошо соответствуют основным ограничениям в оборудовании.

Такие, как:

  1. Размер страницы
  2. пределы
  3. адресного пространства
  4. Выравнивание constaints (DWORD или выравнивание QWORD в целом, обе силы 2)

Для флагов, полномочия 2 всегда есть один бит. Так что такие вещи, как MY_FLAG_1 | MY_FLAG_2 | MY_FLAG_3 | ..., работают только с полномочиями двух. Аналогично для тестирования флажков с &.

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

-2

Поскольку компьютерная память работает с 0/1, которая является двоичной системой.

+0

И какая разница, если я делаю массив из 256 символов вместо 100 символов? – 2009-08-08 17:11:21

+0

Мой ответ связан с тем, как процессор обращается к памяти, проще, когда он 2^n – programmernovice

18

Одна из веских причин - bitmasking. Например, если вы используете константы для представления атрибутов объекта (или чего-то еще), вы можете сохранить много атрибутов в одно целое с помощью битовой маскировки и позже идентифицировать отдельные атрибуты. Отлично подходит для сохранения многих «флагов» в базе данных.

4

Память обычно выделяется кратным размерам страниц из операционной системы, и во многих случаях полезно упорядочить объекты в точности для страниц (чтобы не тратить память). Это зависит от конкретной процедуры распределения, действительно ли это помогает; например если есть неявный заголовок, имеющий размер, равный двум, может фактически повредить.

1

Не так много причин действительно. Из-за выравнивания переменных в структурированном и в стеке, массив из трех байтов, вероятно, займет 4 или 8 байтов в памяти. Я думаю, это просто приятно.

Выделение целого ряда страниц из кучи может работать не так эффективно, как нужно из-за накладных расходов внутренней структуры кучи. Выделение 4096 байт (1 страница для 32-битного оконного компьютера), вероятно, может привести к распределению 4104 байта или более.

Если константы являются флагами, то история очень отличается. Как правило, более эффективно иметь битовые флаги, чем флаги в некоторой базе, которые не являются степенью 2.

2

Наши переменные размеры равны 2 (1, 2, 4 или 8 байтам). Компьютер удобно работает на этих границах. В прежние времена мы тщательно настраивали наши структуры, чтобы сделать наш код быстрее, а иногда проще делать арифметику указателей.

Если у вас есть выбор между размером 256 и 257, мы переходим к 256. Одна из причин заключается в отладке.Когда вы смотрите на память или в файл, ваш отладчик или просмотрщик шестнадцатеричного файла будет показывать данные в строках, которые имеют силу два.

Вот один, который показывает 16 байт в каждой строке, в группах 4.

alt text http://upload.wikimedia.org/wikipedia/en/2/2c/Hexedit-screenshot.png

Для флагов, мы делаем их полномочия двух, чтобы мы могли рассматривать их все по отдельности в одной переменной, а не во многих переменные или массив.

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

bits |= 8;  //00000100 
bits |= 32;  //00010000 

//bits is now 40 00010100 

bits &= 32;  //00010000 

//bits is now 32 00010000 

Многие программисты пишут числа в шестнадцатеричном вместо десятичной, так что это легче увидеть, что происходит с отдельными битами.

1

С бинарными компьютерами удобно использовать стандартные binary multiples, например Mebibyte (или Kibi, Gibi, Tebi ...). Эта мощность 2 чисел также хорошо выглядит в Octal или Hex нотациях.

1

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

Также проще размножаться с использованием одного сдвига, а не общего алгоритма мульпликаций добавления последовательных сдвигов в зависимости от того, установлен ли конкретный бит или нет. OpenGL был известен тем, что требовал от двух текстур текстуры получить доступ к определенным линиям сканирования.

2

Когда дело доходит до размеров массивов, я подозреваю, что есть две причины, по которым предпочтительны полномочия двух. Один из них, о чем свидетельствуют несколько ответов здесь, заключается в том, что программисты, которые не знают, что происходит «под капотом», похоже, имеют общий смысл, что можно как-то более эффективно использовать силу двух. Другой (в основном исторический) относится к циклическим буферам.

Циклические буферы, которые являются степенями двух, могут обрабатываться более легко и быстро, используя маски, для индексов чтения и записи (или указателей) вместо использования обычно более медленной работы по модулю или использования условий, требующих ветвей. Это имело решающее значение для старых машин, но все еще может быть важным для передачи данных больших объемов - например, Графические процессоры

Например, в C, то число байтов, доступных для чтения в циклическом буфере может быть получено:

pending = (SIZE + wr - rd) & (SIZE - 1); 

Если не используя силу двух, то эквивалент будет:

pending = (SIZE + wr - rd) % (SIZE - 1); 

на машинах, которые не реализуют инструкции деление/модуль, который немного «%» может занять несколько сотен циклов, так что вам нужно будет что-то вроде:

if (wr >= rd) 
    pending = wr - rd; 
else 
    pending = (SIZE + wr) - rd; 

Что загромождает код и вызывает ветвление, которое может остановить конвейер команд.

Записи в буфер, который был чем-то вроде

buf[wr++] = x; 
if (wr == SIZE) 
    rd = 0; 

становится (в целом) более эффективным:

buf[wr++] = x; 
wr &= SIZE-1; 

Конечно, если вы использовали беззнаковые 8 разрядные переменный индекс массив 256 записи тогда вам даже не нужно было маскировать.

+0

Хорошая точка. Я все еще думаю на ассемблере и делаю круговые буферы с помощью ands. Когда я создаю триггерную таблицу, я строю ее с 256 "градусами", поэтому я могу смотреть только на нижний байт после сложения или вычитания. – Nosredna