Hitung invers modular

16

Diberi dua angka positif xdan ndengan x<2^n, tulis fungsi sesingkat mungkin untuk dihitung x^-1 mod 2^n. Dengan kata lain, temukan yitu x*y=1 mod 2^n.

Fungsi Anda harus menyelesaikan setidaknya dalam waktu yang wajar n=64, sehingga pencarian lengkap tidak akan berfungsi.

Jika kebalikannya tidak ada, Anda harus menunjukkan itu kepada penelepon entah bagaimana (melemparkan pengecualian, mengembalikan nilai sentinel, dll).

Jika Anda bertanya-tanya harus mulai dari mana, coba Algoritma Euclidean Diperpanjang .

Keith Randall
sumber
ini akan menjadi pernyataan tunggal dalam beberapa perangkat lunak matematika
st0le
1
@ st0le: Benar, dan Anda tidak akan diizinkan untuk menggunakan fungsi seperti itu dalam sistem tersebut. :-D
Chris Jester-Young

Jawaban:

2

Python 95 89

cadalah fungsi anda. Mengembalikan 0 jika tidak ada terbalik (yaitu ketika x genap).

p=lambda x,y,m:y and p(x,y/2,m)**2*x**(y&1)%m or 1
c=lambda x,n:[0,p(x,2**n-1,2**n)][x%2]
Alexandru
sumber
3

Python, 29 byte

lambda x,n:pow(x,2**n-1,2**n)

Ini mengembalikan 0 bahkan x . Ia menggunakan teorema Euler, dengan pengamatan bahwa 2 ^ n - 1 dapat habis dibagi 2 ^ ( n - 1) - 1, melalui eksponensial modular cepat built-in Python. Ini cukup cepat untuk n hingga 7000 atau lebih, di mana ia mulai mengambil lebih dari sekitar satu detik.

Anders Kaseorg
sumber
2

Mathematica - 22

f=PowerMod[#,-1,2^#2]&

f[x,n]kembali ydengan x*y=1 mod 2^n, jika tidakx is not invertible modulo 2^n

branislav
sumber
2

GolfScript (23 karakter)

{:^((1${\.**2^?%}+*}:f;

Hasil sentinel untuk invers yang tidak ada adalah 0.

Ini adalah aplikasi sederhana dari teorema Euler . , jadi x - 1x 2 n - 1 - 1xφ(2n)1(mod2n)x1x2n11(mod2n)

Sayangnya itu eksponensial terlalu besar untuk dihitung secara langsung, jadi kita harus menggunakan loop dan melakukan reduksi modular di dalam loop. Langkah berulang adalah dan kami memiliki pilihan kasus dasar: baik denganx2k1=(x2k11)2×xk=1

{1\:^(@{\.**2^?%}+*}:f;

atau k=2dengan

{:^((1${\.**2^?%}+*}:f;

Saya sedang mengerjakan pendekatan lain, tetapi penjaga itu lebih sulit.

Pengamatan kuncinya adalah kita dapat membangun invers up sedikit demi sedikit: jika xy1(mod2k1)xy{1,1+2k1}(mod2k)xx(y+xy1)1(mod2k)y=(x+1)y1

0x1(mod20)

x(1(x+1)nx)1(mod2n)

x+1 genap.

Itu memberi fungsi 19-char

{1$)1$?@/~)2@?%}:f;

xx&11

{1$.1&+1$?@/~)2@?%}:f;

02n-1 , tapi saya belum membuktikannya.

01(x+1)n11n

{1$.1&*)1$?@/~)2@?%}:f;

nn x f

{..1&*)2$?\/~)2@?%}:f;
Peter Taylor
sumber
1

Ruby - 88 karakter

Gunakan fungsinya f.

def e a,b;a%b==0?[0,1]:(x,y=e(b,a%b);[y,x-(y*(a/b))])end
def f x,n;e(x,2**n)[0]*(x%2)end

Cukup fungsi rekursif dari halaman wiki yang tertaut, mengembalikan 0 pada kesalahan.

Nemo157
sumber
Anda dapat menyimpan beberapa karakter dengan sebaris e: (e=->a,b{...})[x,2**n][0]. Dapat juga menyimpan karakter dengan menguji a%b<1alih-alih a%b==0.
histokrat
1

Haskell, 42 byte

_!1=1
x!n|r<-x!div(n+1)2=(2-r*x)*r`mod`2^n

Menggunakan algoritma berdasarkan lemens Hensel yang menggandakan jumlah digit di setiap iterasi, ini berjalan di bawah satu detik untuk n hingga sekitar 30 juta !

Anders Kaseorg
sumber
1

Pyth , 9 byte

.^Et^2Q^2

Coba di sini!

Mengambil input dalam urutan terbalik. Atau, 9 byte juga: .^EtK^2QK.

Penjelasan

. ^ Et ^ 2Q ^ 2 - Program lengkap.

. ^ - Fungsi Pow. Hal yang sama dengan Python (pow).
  E - Input kedua.
    ^ 2Q - Dan 2 ^ input pertama.
   t - Dikurangi.
       ^ 2 - Dan 2 ^ input pertama lagi.
Tuan Xcoder
sumber
0

GAP, 39 byte

f:=function(x,n)return 1/x mod 2^n;end;

f(x,n)mengembalikan kebalikan dari xmodulo 2^ndan memberikan pesan kesalahan

Error, ModRat: for <r>/<s> mod <n>, <s>/gcd(<r>,<s>) and <n> must be coprime

jika tidak ada terbalik.

ahulpke
sumber