Самый быстрый способ найти силы двух выше, чем число - PullRequest
4 голосов
/ 09 октября 2019

Я пытаюсь найти очень быстрый способ найти следующие более высокие степени 2, чем очень большое число (1 000 000) цифр. Например, у меня есть 1009, и я хочу найти следующие более высокие степени двух, которые равны 1024 или 2 ** 10

Я пытался использовать цикл, но для больших чисел это очень, очень медленно

y=0
while (1<<y)<1009:
   y+=1
print(1<<y)
1024

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

ОТВЕТЫ НА @JonClements

с использованием 2 ** number.bit_length () работает отлично. Так что это будет работать для больших количеств. Спасибо Джону.

Вот пример кода из реализации Джона:

2**j.bit_length() 
1024

Вот пример кода с использованием оператора сдвига

2<<(j.bit_length()-1) 
1024

Вот разница во времени с использованиемчисло миллионов, оператор сдвига и bit_length значительно быстрее:

len(str(aa))
1000000

def useBITLENGTHwithshiftoperator(hm):
  return 1<<hm.bit_length()-1<<1

def useBITLENGTHwithpowersoperator(hm):
  return 2**hm.bit_length()

start = time.time() 
l=useBITLENGTHwithpowersoperator(aa) 
end = time.time() 
print(end - start)                                                                                                                                 
0.014303922653198242                                                                                                                                             

start = time.time() 
l=useBITLENGTHwithshiftoperator(aa) 
end = time.time() 
print(end - start)                                                                                                                                 
0.0002968311309814453

Ответы [ 2 ]

0 голосов
/ 09 октября 2019

Я не пишу код на python, но миллионы цифр означают бигнум так:

  1. попробуйте заглянуть внутрь вашего bignum lib

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

    Как @JonClements предлагает в комментариях, попробуйте bit_length() и измерьте, является ли он O(1) или O(log(n)) ...

  2. Ваш while равен O(n^3) вместо O(n^2)

    В каждой итерации вы сдвигаете биты от 1 снова и снова. Почему бы просто не сдвинуть последний результат на 1 бит? Что-то вроде

     for (y=0,yy=1;yy<1009;y++,yy<<=1);
    
  3. с использованием log2 может быть быстрее

    в случае, если используемый вами класс bignum правильно реализован после некоторого числапорог размера log2(1009) может быть значительно быстрее. Но это зависит от типа используемых вами чисел и самой реализации bignum.

  4. сдвиг битов может быть еще быстрее

    Если у вас есть некоторыеверхний предел для ваших чисел вы можете использовать двоичный поиск , преобразующий ваше битовое смещение в O(n.log2(n)).

    Если нет, вы можете начать битовое смещение на 32 бита вместо 1, когда достигнете целевого размера битовое смещение на 1немного. Или даже использовать больше слоев, таких как 1024/128/16/1 бит. Сложность все равно будет O(n^2), но постоянное время будет в ~ 1024 раза меньше, ускоряя ~ 1024 раза ваш код для больших чисел ...

    Другой вариант - найти ограничение путем сдвига на 1 бит,затем на 2, затем на 4,8,16,32,64, ... до тех пор, пока результат не станет больше целевого числа и оттуда либо сдвиг назад, либо используйте бинарный поиск. Это будет O(n.log2(n)) даже без какого-либо верхнего предела.

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

Построение 2^(y-1) < x <= 2^y также может быть улучшено. Например, используя подход со сдвигом битов, чтобы найти y, вы получите свой ответ как побочный продукт бесплатно. Например, с числами с плавающей запятой или числами с фиксированной запятой вы можете напрямую построить такое число, как вычисляемая экспонента для 1 или установив правильный бит в ноль ... Но для произвольных чисел (где размер числа является динамическим), это намного сложнее / медленнее. Так что все сводится к тому, какой у вас класс bignums и какие значения вы используете.

0 голосов
/ 09 октября 2019

принять 2 ^ потолок (logBase2 (x)) - должно работать, если x не является степенью 2. и вы можете проверить это с помощью: if x==ceiling(x).

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