цепочки умножения, которые приводят к константе по модулю степени 2

Есть ли практический алгоритм, который дает "цепочки умножения"

Чтобы уточнить, цель состоит в том, чтобы произвести замену умножения произвольной и точной длины
Цепочки умножения длины 1 тривиальны.

«Цепочка умножения» будет определена как 2 числа, {начало} и {множитель}, используемые в коде:

 Given a pointer to array of size [{count}]   // count is a parameter
 a = start;
 do 
 {
      a = a * multiplier;  // Really: a = (a * multiplier) MOD (power of 2
      *(pointer++) = a;   
 }
 while (a != {constant} )
 // Postcondition:  all {count} entries are filled.  

Я хочу найти подпрограмму, которая принимает три параметра
1. Степень числа 2
2. Остановка {константа}
3. {count} — количество повторений цикла.

Подпрограмма вернет {start} и {multiplier}.

В идеале значение {Constant}, равное 0, должно быть допустимым.

Тривиальный пример:

power of 2 = 256  
stopping constant = 7
number of times for the loop = 1  
returns {7,1} 

Нетривиальный пример:

power of 2 = 256  
stopping constant = 1
number of times for the loop = 49
returns {25, 19}  

Максимальное значение {count} для данной степени числа 2 может быть довольно небольшим.
Например, 2^4 (16) кажется ограниченным числом 4.


person Procedural Throwback    schedule 01.11.2008    source источник
comment
Я не понимаю, какое отношение к этому имеет Сила числа 2... почему это закомментировано и что означает этот комментарий?   -  person Paige Ruten    schedule 01.11.2008
comment
Непонятно и количество шагов. Предположительно, это своего рода верхняя граница допустимого количества циклов умножения.   -  person Jonathan Leffler    schedule 01.11.2008
comment
{a} — стандартный целочисленный тип, например. 8, 16, 32 или 64 бита, поэтому умножение неявно сокращается до размера выходного типа.   -  person Procedural Throwback    schedule 01.11.2008
comment
@Jeremy: я думаю, что цель степени 2 показана в комментарии.   -  person Jonathan Leffler    schedule 01.11.2008
comment
Так почему бы не вернуть multiplier=1 и start=constant? Эта спецификация проблемы кажется неясной и немотивированной.   -  person Darius Bacon    schedule 01.11.2008


Ответы (3)


Вот метод вычисления значений для начала и множителя для случая, когда константа нечетная:

  1. Найдите такое нечетное m (m = множитель), чтобы порядок m по модулю 2 ^ D был не менее подсчета, что означает, что наименьшее n такое, что m ^ n = 1 (mod 2 ^ D), не менее подсчета. Я не знаю другого способа найти такое m, кроме как сделать случайное предположение, но после небольшого эксперимента выяснилось, что половина нечетных чисел от 1 до 2^D имеет максимальный порядок 2^(D-2). (Я пробовал для D максимум 12.)

  2. Вычислить x так, чтобы x * m^count = 1 (mod 2^D) и установить start = x * константа (mod 2^D).

Такой x можно найти с помощью «расширенного алгоритма Евклида»: учитывая a и b без общего делителя, он дает вам x и y такие, что a * x + b * y = 1. Здесь a = m ^ count mod 2 ^ D и б = 2^D.

редактировать: если константа оказывается четной, вы можете разделить ее на степень 2, скажем, 2^k, чтобы получить нечетную, а затем сделать вышеописанное для ввода {constant/2^k, count , 2^(D-k)} и, наконец, вернуть {start*2^k,multiplier}.

person mattiast    schedule 01.11.2008
comment
Действительно приятно - я видел циклы 2 ^ (D-2), но не пошел дальше. Для даже «c» есть циклы до 2 ^ (D-3), разве не должно работать что-то подобное? - person Procedural Throwback; 01.11.2008
comment
Теперь это должно сделать это для случаев, когда c не равно нулю. - person mattiast; 01.11.2008
comment
Это имеет смысл, и это объясняет, почему длина цикла для некоторых четных # была намного короче, поскольку мне нужно искать в диапазоне 2 ^ (D-k). - person Procedural Throwback; 01.11.2008
comment
С нечетными множителями (относительно простыми до 2 ^ D) нечетные начальные точки дают максимальную длину цикла, четные начальные точки короче, но все равно никогда не достигают 0. Таким образом, остается, чтобы четные множители достигли 0, и осталась только длина? - person Procedural Throwback; 01.11.2008
comment
Я вижу, для четных делителей степень 2 определяет количество, но я еще не совсем уверен, как получить промежуточное значение. Что с теми другими нечетными множителями, которые не образуют цикл? Разве любая относительно простая пара не должна образовывать цикл? - person Procedural Throwback; 01.11.2008
comment
Если константа равна нулю, вам нужно D ›= count. В этом случае вы можете выбрать multiplier=2 и start=2^(D-count) - person mattiast; 01.11.2008
comment
Для C = 0 у меня есть D - (младшие 0 битов начала и множителя) в качестве счетчика. Выше первого 1 бита остальные кажутся произвольными. - person Procedural Throwback; 02.11.2008
comment
Для шага 1 похоже, что есть лучший способ, чем угадывать, хотя я не могу понять, почему. Первые 2 значения m всегда равны 3,5. -3/-5 mod 2^D также заполнены. Начиная с 3 или 5, любая вторая мощность работает? - person Procedural Throwback; 02.11.2008

Вы запрашиваете нетривиальные решения следующего модульного уравнения:

s * m^N = C (mod 2^D)

куда

  • s - начальная константа
  • m - множитель
  • N - количество итераций (задается задачей)
  • C - конечная константа (заданная задачей)
  • D - показатель степени числа 2 (данный задачей)

Взгляните на теорему Эйлера в теории чисел.

Для произвольного нечетного m (которое является простым с 2^D) у вас есть

m^phi(2^D) = 1 (mod 2^D)

таким образом

C * m^phi(2^D) = C (mod 2^D)

и наконец

C * m^(phi(2^D)-N) * m^N = C (mod 2^D)

Брать

s = C * m^(phi(2^D)-N)

и вы сделали. фи-функция Эйлера степени двойки половина эта степень числа 2, то есть:

phi(2^D) = 2^(D-1)

Пример. Позволять

  • N = 5
  • C = 3
  • 2^D = 16
  • фи(16) = 8

Выберите произвольно m = 7 (нечетное) и вычислите

3 * 7^(8-5) = 1029
s = 1029 mod 16 = 5

В настоящее время

s * m^N = 5 * 7^5 = 84035
84035 mod 16 = 3 == C
person Federico A. Ramponi    schedule 01.11.2008
comment
С нечетным m я не могу достичь 0, что имеет смысл теперь, когда я вижу уравнение. С четным «m» он в конечном итоге достигнет 0. Есть ли другая форма уравнения, чтобы получить константу 0. - person Procedural Throwback; 01.11.2008
comment
если C равно 0, то вы можете выбрать s = C*... = 0 (это снова тривиальное решение...) - person Federico A. Ramponi; 01.11.2008
comment
Как так? C = 0, N = 13, 2 ^ D = 256 Start = 0 не удовлетворяет N = 13 - person Procedural Throwback; 01.11.2008
comment
Обратите внимание, что мой ответ дает s, m такие, что после ровно N итераций вы достигнете C. Но вы также можете достичь C за менее чем N итераций, т. е. вы можете выполнить цикл несколько раз. между последовательностью чисел x, y, z, C, x, y, z, C... - person Federico A. Ramponi; 01.11.2008
comment
Можно ли изменить это, чтобы дать первый C (поскольку это было бы условием завершения цикла while)? - person Procedural Throwback; 01.11.2008
comment
Возможно, применив еще немного теории чисел, вы сможете явно вычислить m так, что циклу потребуется ровно N шагов (не меньше), чтобы достичь конечной константы. - person Federico A. Ramponi; 01.11.2008
comment
Любые мысли о том, где начать искать этот кусок, и как я могу перефразировать вопрос? - person Procedural Throwback; 01.11.2008
comment
Я думал, что нечетный случай будет работать для точного, но для {s=3,m=7} получается 3, 3*7=21 и 16 = 5, 5*7=35 % 16 = 3 - person Procedural Throwback; 01.11.2008

Почему это не удовлетворяет требованиям?

start = constant;
multiplier = 1;

Обновление: теперь я вижу, что количество циклов является одним из входных параметров. Похоже, что эта проблема является частным случаем или, по крайней мере, связана с дискретным логарифмом проблема.

person Greg Hewgill    schedule 01.11.2008
comment
Эээ... да. Поэтому, вероятно, «начало» должно быть четвертым параметром процедуры (при условии, что цель количества шагов выяснена). - person Jonathan Leffler; 01.11.2008
comment
Да, это тривиальный случай, когда количество циклов равно 1. Количество циклов является параметром алгоритма расчета. - person Procedural Throwback; 01.11.2008