Почему мы всегда объявляем константы властью 2?

Большинство констант, которые я вижу в другом коде, имеют степень 2, т.е.

#define SIZE 256

или

public static final int SIZE = 2048;

Есть ли какая-то особая причина, почему мы делаем это вместо i.e.

#define SIZE 257

?

Ответ 1

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

Например:

  • Размер страницы
  • Ограничения адресного пространства
  • Концентрации выравнивания (выравнивание по DWORD или QWORD, как правило, 2)

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

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

Ответ 2

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

Ответ 3

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

Ответ 4

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

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

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

alt text
(источник: wikimedia.org)

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

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

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

//bits is now 40   00010100

bits &= 32;      //00010000

//bits is now 32   00010000

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

Ответ 5

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

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

Например, в 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-строчный массив, вам даже не нужно было маскировать.

Ответ 6

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

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

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

Ответ 7

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

Ответ 8

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

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

Ответ 9

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