#python #python-2.7
#python #python-2.7
Вопрос:
Мне нужно вычислить:
x=(x*a b)/2 % 2**128
много раз. x, a, b — 128-битные числа (выбираются случайным образом). Как сделать это самым быстрым способом? Я подумал о numpy, может ли это как-то помочь? Теперь это примерно в 100 раз медленнее… Есть ли способ сделать это быстрее? Конечно, это нужно делать отдельно, шаг за шагом, алгоритм более сложный, чем этот (a, b изменяется через несколько шагов), поэтому мы не можем пытаться выполнять здесь какую-либо математику или быстрое возведение в степень.
Пример более полного кода:
a=333
b=555
c=777
d=999
x=12345
for i in range(128):
if x % 2 == 1:
x=((x * a b)/2) % 340282366920938463463374607431768211456
else:
x=(x * c/2 d) % 340282366920938463463374607431768211456
print(x)
Комментарии:
1. Почему вы используете Python 2? Срок его службы истек.
2. Что вы подразумеваете под » вычислением «? Вы решаете уравнение?
3. Простым шагом является предварительное вычисление 2 ** 128.
4. В каком формате или структуре данных находятся многие
x
s? И что вы имеете вa
виду под иb
изменением, изменением как? Вы вычисляете деление на 2 по модулю 2 ^ 128 — я предполагаю, что вы вычисляете целочисленные значения и не заботитесь о том, чтобы нечетные числа делились на 2? Это также означает, что вы можете получить более быстрые результаты путем сдвига битов вместо фактического умножения и деления, поскольку все это степени 2.5. Пожалуйста, изучите битовые операции Python. Это почти наверняка быстрее с операциями сдвига и маски. Более того, я предполагаю, что вы работаете со 128-битным линейным конгруэнтным генератором случайных чисел. Если это так, то публикация этих вопросов предполагает, что вы должным образом не исследовали эту парадигму, потому что тогда у вас уже были бы реализованы побитовые операции.
Ответ №1:
У вас возникнут некоторые проблемы из-за того, что вы выполняете неэффективные операции: 128-битные целые числа не являются родными для большинства реализаций Python и будут подвергаться штрафам за операции longint. Однако вы можете сократить время выполнения примерно на 20%, если будете использовать операции сдвига и маски вместо деления и деления по модулю на степени 2:
import timeit
a=333
b=555
c=777
d=999
x=12345
two_128 = 2 ** 128
mask = two_128 - 1
def rng_orig(x):
for i in range(128):
if x % 2 == 1:
x=((x * a b)/2) % two_128
else:
x=(x * c/2 d) % two_128
def rng_bit(x):
for i in range(128):
if x amp; 1:
x=((x * a b) >> 1) amp; mask
else:
x=(x * (c >> 1) d) amp; mask
repeat = 100000
print(timeit.timeit(lambda: rng_orig(x), number = repeat))
print(timeit.timeit(lambda: rng_bit (x), number = repeat))
Результаты синхронизации:
5.1968478000000005
3.965898900000001
Комментарии:
1. Спасибо. Это работает! Я где-то читал об этом, я подумал, что это можно сделать по-другому, но не знал точно, как. Теперь это кажется очевидным и тривиальным.
2. Что-то здесь не так: x=(x * (c >> 1) d) . Оно не равно x=(x * c / 2 d). Также x=(x * (c / 2) d) не равно x=(x * c / 2 d). x= (x * c >> 1 d) также неверно.
3. Я думаю, что я это исправил. Это может быть x=((x >> 1) * c d).
Ответ №2:
Если предполагается, что это целочисленная арифметика, вы должны использовать целочисленные деления. Это позволит избежать ненужного преобразования в числа с плавающей запятой. Кроме того, использование побитовых операций для модуля, вероятно, будет быстрее.
mask128 = 2**128 - 1
x = ( (x*a b)//2 ) amp; mask128
Комментарии:
1. Да, я работаю только с целыми числами. Я попробую.