Как говорили в комментариях:
if(SQRT[a*a+b*b]>something)
это ужасный пример использования регистра. Если это все, что вам нужно SQRT, просто квадрат something
.
До тех пор, пока вы можете сообщить компилятору, что SQRT
не имеет ничего подобного, тогда цикл времени выполнения сделает ваш исполняемый файл меньшим и добавит лишь незначительное количество накладных расходов процессора во время запуска. Определенно использовать uint8_t
, а не int
. Загрузка 32-разрядного временного из 8-битной памяти не медленнее, чем из ячейки памяти с 32-разрядной памятью. (Дополнительная инструкция movsx
на x86 вместо использования операнда памяти будет более чем оплачивать себя при уменьшенном загрязнении кэша. RISC-машины обычно не позволяют использовать операнды памяти, поэтому вам всегда нужна инструкция для загрузки значения в регистр .)
Кроме того, sqrt
- 10-21 период времени на Sandybridge. Если вам это не нужно часто, цепочка int-> double, sqrt, double-> int не намного хуже, чем кэш L2. И лучше, чем перейти к L3 или основной памяти. Если вам нужно много sqrt
, то обязательно сделайте LUT. Пропуск будет намного лучше, даже если вы подпрыгиваете в таблице и вызывают промахи L1.
Вы могли бы оптимизировать инициализацию путем возведения в квадрат вместо sqrting, с чем-то вроде
uint8_t sqrt_lookup[65536];
void init_sqrt (void)
{
int idx = 0;
for (int i=0 ; i < 256 ; i++) {
// TODO: check that there isn't an off-by-one here
int iplus1_sqr = (i+1)*(i+1);
memset(sqrt_lookup+idx, i, iplus1_sqr-idx);
idx = iplus1_sqr;
}
}
Вы все еще можете получить преимущества наличия sqrt_lookup
быть const
(компилятор знает, что не может псевдоним). Либо используйте restrict
, либо ложь компилятору, поэтому пользователи таблицы видят массив const
, но вы на самом деле пишете ему.
Это может быть связано с ложью компилятору, поскольку оно объявлено в большинстве мест extern const
, но не в файле, который его инициализирует. Вы должны убедиться, что это действительно работает, и не создает код, ссылающийся на два разных символа. Если вы просто отбрасывали const
в функции, которая инициализирует его, вы можете получить Segfault если компилятор поместил его в rodata
(или только для чтения bss
памяти, если это неинициализированное, если это возможно на некоторых платформах?)
Может быть мы можем избежать лжи компилятора, с:
uint8_t restrict private_sqrt_table[65536]; // not sure about this use of restrict, maybe that will do it?
const uint8_t *const sqrt_lookup = private_sqrt_table;
на самом деле, это просто const
указатель на const
данные, не является гарантией того, что он направлен не может быть изменена на другую ссылку.
Время доступа будет таким же, но инициализация/заполнение массива будет резко отличаться. – Nawaz
Это действительно будет очень зависимым от компилятора и реализации. Если вы заинтересованы в оптимизации, выполняемой конкретным компилятором архитектуры, добавьте это – Vality
. Кроме того, рассмотрите возможность создания массива 'uint8_t', чтобы общий размер массива был меньше. Также следует избегать квадратных корней; обычно 'a * a + b * b> что-то« что-то »лучше (хотя в этом случае это не идентичный тест на то, что вы написали). – Hurkyl