2015-07-11 2 views
1

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

Math.abs(((a*k + b) % P) % m); 

P является константой простое число
m не является отрицательной и мощностью 2
a и b являются случайными неотрицательное числа

Примечание: Для того, чтобы быть ясно, что это не горячее пятно, которое я обнаружил во время профилирования, и хочу улучшить. Я заинтересован в поиске, если есть способ написать выражение лучше (с точки зрения эффективности), которое может быть легко известно кому-то с лучшим фоном в битовых операциях, например.

+2

Если ваш код работает, и вы просите улучшения, вы должны, вероятно, задать этот вопрос на http://codereview.stackexchange.com/. – Pshemo

+0

@Pshemo: Это SE также для вопросов оптимизации или только для подходов стиля кода/дизайна? – Cratylus

+0

Являются ли 'P' и' m' полезными или только некоторые случайные значения? – harold

ответ

2

Резюмируя комментарий цепь, вы могли бы написать

(a * k + b) % P & (m - 1) 

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

В этом новом выражении единственным оставшимся mod-операцией является константа, которую любой респектабельный компилятор оптимизирует по тем же линиям, что и оптимизирует деление на константу.

+0

1) Моей единственной проблемой является то, что тот факт, что 'не эквивалентен к оригинальному выражению' может иметь какое-то негативное влияние, поскольку это универсальная хеш-функция. 2) Существует ли какой-либо * вид изменения *, если * 'm' были также первичными? – Cratylus

+0

@Cratylus, если 'm' не является силой двух, вся сделка' & (m - 1) 'ломается ужасно. Но с PoT 'm' не должно быть никаких негативных последствий, негативы просто« зеркалируются », это никак не влияет на равномерность распределения. И на самом деле, в некотором смысле это может быть даже «более правильным», поскольку математика хэширования всегда беззнаковая (так что «%» должен быть «Integer.remainderUnsigned») – harold

1

Это получает аналогичный ответ («аналогичные» означает «тот же результат, когда выражение в скобках не является отрицательным, но отличается при отрицательном), но с использованием немного кунг-фу, чтобы избежать разделения модуль и вызов Math.abs():

(a*k + b) % P & ~-m 

Чтобы понять, что происходит, давайте предположим, m = 8 и посмотреть на 16-битных битовых комбинаций:

8 -> 0000 1000 
-8 -> 1111 1000 
~-8 -> 0000 0111 

Как вы можете видеть, ~-m производит бит mask вам нужно замаскировать все, кроме бит, необходимых для результата n % m - то есть высокий бит (бит отрицательного индикатора) и все, кроме бит справа от 1 бит, используемого для мощности 2-го номера.

На личной ноте, я совершенно очарован с выражением ~-m, который при операции AND с предыдущим расчетом достигает как abs() (путем битового маскирования старший бит) и эффективно делает модуль разделения, когда m является силой из двух.

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

+0

Btw, '~ -m == (m - 1) '. – harold

+0

@harold да, я предположил, что это будет быстрее, однако я просто сделал тест, а '~ -m' примерно на 20% медленнее, чем' m - 1'. Это может по-прежнему быть полезным для тех, кто хочет решить головоломку, отрицающую использование вычитания. – Bohemian

+0

Интересно, я не ожидал никакой разницы (разве компиляторы не должны знать эту личность?) – harold

 Смежные вопросы

  • Нет связанных вопросов^_^