Расширенный евклидов алгоритм является хорошим решением для этого, но он слишком сложен и труден для реализации.Есть лучший.
И есть еще один способ сделать это (спасибо моему другу (:)
В wikipedia есть хорошая статья - модульный мультипликативный обратный с использованием теоремы Эйлера в случае, когда m
и a
взаимно просты:
, где φ(m)
равно Функция Эйлера .
В моем случае m
(по модулю) - это размер типа хэша - 2^32
, 2^64
и т. Д. (В моем случае - 64 бита).
Ну, это означает, что мы должны найти только значение φ(m)
. Но подумайте об этом - m == 2 ^ 64
, так что это дает нам гарантию, что m
будет взаимно простым со всеми нечетнымичисла и НЕ будут взаимно простыми для любого четного числа . Итак, нам нужно получить число всех значений и разделить их на 2.
Кроме того, мы знаем, что m
будет без знака, так как в противном случае у нас возникнут некоторые проблемы. Чем это даст нам возможность сделать это:
hash_t x = -1;
x /= 2;
hash_t a_reverse = fast_pow( a, x );
Ну, насчет 64-битных чисел, x
- это действительно большое число (19 цифр: 9 223 372 036 854 775 807
), но fast_pow
действительно быстрое, и мы можем кэшировать обратное число, если нам нужно более одного запроса.
fast_pow
- это хорошо известный алгоритм:
hash_t fast_pow( hash_t source, hash_t pow )
{
if( 0 == pow )
{
return 1;
}
if( 0 != pow % 2 )
{
return source * fast_pow( source, pow - 1 );
}
else
{
return fast_pow( source * source, pow / 2 );
}
}
Добавление: например:
hash_t base = 2305843009213693951; // 9th mersenne prime
hash_t x = 1234567890987654321;
x *= fast_pow( base, 123456789 ); // x * ( base ^ 123456789 )
hash_t y = -1;
y /= 2;
hash_t base_reverse = fast_pow( base, y );
x *= fast_pow( base_reverse, 123456789 ); // x * ( base_reverse ^ 123456789 )
assert( x == 1234567890987654321 ) ;
работает отлично и очень быстро.