Модульна мультиплікативна обернена


22

Ваше завдання - дати два цілих числа aта bобчислити модульну мультиплікативну зворотну модуль b, якщо вона існує.

Модульна інверсія aмодуля b- це число cтаке, що ac ≡ 1 (mod b). Цей номер є унікальним модулем bдля будь-якої пари aта b. Він існує лише в тому випадку, якщо найбільший спільний дільник aі bє 1.

Сторінку Wikipedia для модульного мультиплікативного зворотного можна звернутися , якщо вам необхідна додаткова інформація про тему.

Вхід і вихід

Введення задається як два цілих числа, або список двох цілих чисел. Ваша програма повинна виводити або одне число, модульну мультиплікативну зворотну, яка знаходиться в інтервалі 0 < c < b, або значення, що вказує на відсутність зворотного. Значення може бути будь-яким, крім числа в діапазоні (0,b), а також може бути винятком. Однак значення має бути однаковим для випадків, коли немає зворотного.

0 < a < b можна припустити

Правила

  • Програма повинна закінчитися в якийсь момент і повинна вирішити кожен тестовий випадок менше ніж за 60 секунд
  • Застосовуються стандартні лазівки

Тестові кейси

Нижче наведено тестові приклади у форматі, a, b -> output

1, 2 -> 1
3, 6 -> Does not exist
7, 87 -> 25
25, 87 -> 7
2, 91 -> 46
13, 91 -> Does not exist
19, 1212393831 -> 701912218
31, 73714876143 -> 45180085378
3, 73714876143 -> Does not exist

Оцінка балів

Це код гольфу, тому виграє найкоротший код для кожної мови.

Це та це подібні запитання, але обидва задають конкретні ситуації.


6
З Малої теореми Ферма випливає, що мультиплікативна інверсія a, якщо вона існує, може бути обчислена ефективно як ^ (phi (b) -1) mod b, де phi - тотативна функція Ейлера: phi (p0 ^ k0 * p1 ^ k1 * ...) = (p0-1) * p0 ^ (k0-1) * (p1-1) * p1 ^ (k1-1) * ... Не кажучи, що це призводить до скорочення коду :)
ngn

1
@Jenny_mathy Внесення додаткових вводів, як правило, заборонено.
Містер Xcoder

3
Я підраховую шість відповідей, які здаються грубими, і навряд чи запускати всі тестові справи за 60 секунд (деякі з них спочатку дають стек або помилку пам'яті).
Ørjan Johansen

1
@ngn: Ви зв'язали Малу теорему Ферма (FLT) з вдосконаленням Ейлера. Фермат не знав про функцію Ейлера фі. Крім того, поліпшення FLT та Ейлера застосовуються лише у випадку, якщо gcd (a, b) = 1. Нарешті, у формі, яку ви це записали, "a ^ (\ phi (b) -1) mod b" відповідає 1, а не a ^ (- 1). Щоб отримати ^ (- 1), використовуйте ^ (\ phi (b) -2) мод b.
Ерік Тауерс

1
@EricTowers Euler's є наслідком. Щодо "gcd (a, b) = 1" - я сказав "якщо він [зворотний] існує". Ви впевнені у фі (б) -2?
ngn

Відповіді:


11

Математика, 14 байт

Обов’язковий математичний вбудований :

ModularInverse

Це функція, яка бере два аргументи ( aі b), і повертає зворотний бік mod b, якщо він існує. Якщо ні, то повертається помилка ModularInverse: a is not invertible modulo b..


7

JavaScript (ES6), 79 73 62 61 байт

Повертається, falseякщо обернення не існує.

Він використовує розширений евклідовий алгоритм і майже миттєво вирішує всі тестові випадки.

f=(a,b,c=!(n=b),d=1)=>a?f(b%a,a,d,c-(b-b%a)/a*d):b<2&&(c+n)%n

Тестові кейси


Чому не можна записати ім’я функції f, як у f (c, a, b = 0, d = 1, n = a) => c? F (a% c, c, d, b- ( aa% c) / c * d, n): a <2 && (b + n)% n?
RosLuP

@RosLup f(x,y)завжди аналізується як виклик функції, за винятком випадків, коли йому явно передує functionключове слово. З іншого боку, функція анонімної стрілки оголошується як (x,y)=>somethingта f=(x,y)=>somethingпризначає функцію fзмінній.
Арнольд

4

Желе , 2 байти

æi

Спробуйте в Інтернеті!

При цьому використовується вбудований модульний інверс, а повернення 0 - для модульної інверсії.

Желе , 7 байт

R×%⁸’¬T

Спробуйте в Інтернеті!

Виводить порожній набір (представлений у вигляді порожнього рядка) на жодній модульній звороті. Витрачає пам’ять у TIO для найбільших тестових випадків, але має працювати з достатньою кількістю пам'яті.

Як це працює

R×%⁸’¬T  
R        Generate range of b
 ×       Multiply each by a
  %⁸     Mod each by b
    ’    Decrement (Map 1 to 0 and all else to truthy)
     ¬   Logical NOT
      T  Get the index of the truthy element.

Якщо ви хочете працювати на більших тестових випадках, спробуйте цю (відносно необов’язану) версію, яка вимагає багато часу, а не пам’яті:

Желе, 9 байт

×⁴%³’¬ø1#

Спробуйте в Інтернеті!

Як це працює

×⁴%³’¬ø1#
        #   Get the first
      ø1      one integer
            which meets:
×⁴            When multiplied by a
  %³          And modulo-d by b
    ’         Decrement
     ¬        Is falsy

4

Python 2 , 34 байти

f=lambda a,b:a==1or-~b*f(-b%a,a)/a

Спробуйте в Інтернеті!

Рекурсивна функція , яка дає Trueдля print f(1,2), який я вважаю прийнятними, і помилки для недійсних входів.

хах1(модб)

ах-1=кбк

Приймаючи мода-1кб(мода)-кб1(мода)к

кf(-б%а,а)

ааб

ках-1=кбхкб+1а


3

R + числа , 15 байт

numbers::modinv

повертає NAдля тих, хто aне обертає мод b.

R-Fiddle, щоб спробувати!

R , 33 байти (не конкуруючий)

Це не вдасться в дуже великих bрозмірах, оскільки воно фактично створює вектор 32*bбіт розміру .

function(a,b)which((1:b*a)%%b==1)

Спробуйте в Інтернеті!

Повертає integer(0)(порожній список) для тих, хто aне перевертає мод b.



3

Python 2 , 51 49 54 53 51 49 bytes

-1 байт завдяки офіалаімм
-1 байт завдяки Шаггі

a,b=input()
i=a<2
while(a*i%b-1)*b%a:i+=1
print+i

Спробуйте в Інтернеті!

Друкує, 0коли немає рішення.


1
Виходи 0для a=1та b=2; з тестових випадків він повинен виводити 1.
Shaggy


1
Як зазначав Шаггі, не вдається2, 1
містер Xcoder

@Shaggy має працювати зараз
Rod

Це не вдається повернути відповідь за 60 секунд (на TIO) на вхід 31,73714876143.
Ільмарі Каронен

3

Japt , 9 8 байт

Приймає введення в зворотному порядку. Виходи -1без збігу. Вибивається, коли велике ціле число стає більшим.

Ç*V%UÃb1

Перевірте це

  • Збережено 1 байт завдяки ETH, що вказує на помилковий та дуже очевидний простір.

73714876143,31Здається, тестовий вхід створює помилку, що не в пам'яті, на Firefox (і виходить з ладу Chromium). Я не думаю, що це правильна відповідь.
Ільмарі Каронен

@IlmariKaronen: Я чітко вказав на цей факт у своєму рішенні. Ми можемо вважати нескінченну пам'ять для цілей гольфу з кодом, щоб проблеми з пам'яттю та збої не приводили до недійсності цього рішення.
Кудлатий

1
На жаль, проблеми з пам'яттю також не дають змоги визначити, чи дійсно ваш код вирішить тестові випадки за 60 секунд, як це передбачено викликом. Я підозрюю, що цього не вдасться, навіть якщо б було достатньо пам'яті, щоб вона не вийшла з ладу, але без комп’ютера, який би міг насправді запустити програму так довго, не можна точно сказати.
Ільмарі Каронен


2

Python 3 , 49 байт

lambda a,b:[c for c in range(b)if-~c*a%b==1][0]+1

Спробуйте в Інтернеті!

Python 3 , 50 байт

lambda a,b:[c for c in range(1,b+1)if c*a%b==1][0]

Спробуйте в Інтернеті!

Це кидає IndexError: list index out of rangeу випадку, якщо немає модульної мультиплікативної зворотної, як це дозволено правилами.


Це не вдається повернути результат за вхід 31,73714876143за 60 секунд (на TIO).
Ільмарі Каронен

@IlmariKaronen Здається, закінчиться за 56 секунд на моїй машині (Macbook Pro '15)
Містер Xcoder

2

8 , 6 байт

Код

invmod

Пояснення

invmod8-е слово, яке обчислює значення зворотного aмодуля b. Він повертається nullпри переповненні чи інших помилках.

Використання та тестові кейси

ok> 1 2 invmod .
1
ok> 3 6 invmod .
null
ok> 7 87 invmod .
25
ok> 25 87 invmod .
7
ok> 2 91 invmod .
46
ok> 13 91 invmod .
null
ok> 19 1212393831 invmod .
701912218
ok> 31 73714876143 invmod .
45180085378
ok> 3 73714876143 invmod .
null


2

J , 28 байт

4 :'(1=x+.y)*x y&|@^<:5 p:y'

Спробуйте в Інтернеті!

Використовує теорему Ейлера . Повертає 0, якщо обернено не існує.

Пояснення

4 :'(1=x+.y)*x y&|@^<:5 p:y'  Input: a (LHS), b (RHS)
4 :'                       '  Define an explicit dyad - this is to use the special
                              form `m&|@^` to perform modular exponentiation
                          y   Get b
                      5 p:    Euler totient
                    <:        Decrement
             x                Get a
                   ^          Exponentiate
               y&|@             Modulo b
       x+.y                   GCD of a and b
     1=                       Equals 1
            *                 Multiply

2

Pyth , 10 байт

3 байти збережено завдяки @Jakube .

xm%*szdQQ1

Спробуйте тут!

Повертається -1без мультиплікативного зворотного.

Розбивка коду

xm%*szdQQ1      Let Q be the first input.
 m      Q       This maps over [0 ... Q) with a variable d.
   *szd         Now d is multiplied by the evaluated second input.
  %    Q        Now the remained modulo Q is retrieved.
x        1      Then, the first index of 1 is retrieved from that mapping.

Pyth , 15 13 байт

KEhfq1%*QTKSK

Викидає виняток, якщо не існує мультипликативного зворотного.

Спробуйте тут!

Pyth , 15 байт

Iq1iQKEfq1%*QTK

Це додає багато байтів для обробки справи, коли такої кількості немає. Програму можна значно скоротити, якщо з цим випадком не потрібно було б звертатися:

fq1%*QTK

Спробуйте тут!


2 байти збережено за допомогоюKExm%*QdKK1
Jakube

Або 3 байти, якщо поміняти порядок введення даних:xm%*szdQQ1
Jakube

@Jakube Дякую, редагування!
Містер Xcoder

Як це працює?
Kritixi Lithos

@Cowsquack Я додав повністю примітивний розбиття коду, але у мене немає часу включати повне пояснення. Сподіваюсь, це поки що досить зрозуміло, але я спробую найближчим часом додати більш повне пояснення.
Містер Xcoder

1

C (gcc) , 115 байт

#define L long long
L g(L a,L b,L c,L d){return a?g(b%a,a,d-b/a*c,c):b-1?0:d;}L f(L a,L b){return(g(a,b,1,0)+b)%b;}

Спробуйте в Інтернеті!

Розширений евклідовий алгоритм, рекурсивна версія

C (gcc) , 119 байт

long long f(a,b,c,d,t,n)long long a,b,c,d,t,n;{for(c=1,d=0,n=b;a;a=t)t=d-b/a*c,d=c,c=t,t=b%a,b=a;return b-1?0:(d+n)%n;}

Спробуйте в Інтернеті!

Розширений евклідовий алгоритм, ітеративна версія


1

C (gcc) , 48 110 104 байт

#define f(a,b)g(a,b,!b,1,b)
long g(a,b,c,d,n)long a,b,c,d,n;{a=a?g(b%a,a,d,c-(b-b%a)/a*d):!--b*(c+n)%n;}

Спробуйте в Інтернеті!

Це має працювати з усіма входами (які підходять протягом тривалого часу) протягом 60 секунд.

Редагувати. Я вже зловживаю nзмінною, тому я можу також припустити, що gcc ставить перше завдання у %rax.


1
На жаль, це дає неправильні результати навіть для досить невеликих входів через ціле переповнення всередині циклу. Наприклад, f(3,1000001)повертає 717, що, очевидно, нісенітниця (правильна відповідь - 333334). Крім того, навіть якби ця помилка була виправлена ​​за допомогою ширшого цілого типу, цей підхід грубої сили неодмінно затримався б для деяких великих тестових випадків, поданих у виклику.
Ільмарі Каронен


0

Аксіома, 45 байт

f(x:PI,y:PI):NNI==(gcd(x,y)=1=>invmod(x,y);0)

0 для помилки інакше повернути z з x * z Mod y = 1


0

Python 2 , 52 байти

-3 байти завдяки панові Xcoder.

f=lambda a,b,i=1:i*a%b==1and i or i<b and f(a,b,i+1)

Спробуйте в Інтернеті!

Вихідні дані Falseне мають рішення та помилки, оскільки bзбільшується.

Вбудований TIO

Я просто випробовую iframe в Stack Snippets і вони працюють абсолютно фантастично.


Я не впевнений, що це працює, не може i*a%bбути 0?
Пшеничний майстер

Не вдається помилка з "перевищеною максимальною глибиною рекурсії" для введення (31,73714876143).
Ільмарі Каронен

0

JavaScript (ES6), 42 41 39 38 байт

Виходи falseбез збігу. Викине помилку переповнення, оскільки друге число стане занадто великим.

x=>y=>(g=z=>x*z%y==1?z:z<y&&g(++z))(1)

0

Желе , 27 байт

²%³
⁴Ç⁹Сx⁸
ÆṪ’BṚçL$P%³×gỊ¥

Спробуйте в Інтернеті!

Використовує теорему Ейлера з модульною експоненцією. Оскільки в Jelly немає вбудованого модуля для виконання модульної експоненції, його потрібно було реалізувати, і він займав більшість байтів.


0

Аксіома, 99 байт

w(a,b,x,u)==(a=0=>(b*b=1=>b*x;0);w(b rem a,a,u,x-u*(b quo a)));h(a,b)==(b=0=>0;(b+w(a,b,0,1))rem b)

вона використовує функцію h (); h (a, b) повернути 0, якщо помилка [не існує зворотної], інакше вона поверне z таким, що a * z mod b = 1 Це було б нормально, навіть якщо аргументи негативні ...

це була б загальна функція egcd (), яка перезавантажує список int (тому вони також можуть бути негативними)

egcd(aa:INT,bb:INT):List INT==
   x:=u:=-1   -- because the type is INT
   (a,b,x,u):=(aa,bb,0,1)
   repeat
      a=0=>break
      (q,r):=(b quo a, b rem a)
      (b,a,x,u):=(a,r,u,x-u*q)
   [b,x, (b-x*aa)quo bb]

ось як це використовувати

(7) -> h(31,73714876143)
   (7)  45180085378
                                                    Type: PositiveInteger

Я знаходжу базовий альго в Інтернеті від https://pastebin.com/A13ybryc

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.