Calcular modular inverso


16

Dados dos números positivos xy ncon x<2^n, escriba la función más corta posible para calcular x^-1 mod 2^n. En otras palabras, encuentre ytal que x*y=1 mod 2^n.

Su función debe completarse en un tiempo razonable al menos n=64, por lo que una búsqueda exhaustiva no funcionará.

Si el inverso no existe, debe indicarlo al llamador de alguna manera (lanzar una excepción, devolver un valor centinela, etc.).

Si se pregunta por dónde comenzar, pruebe el Algoritmo Euclidiano Extendido .


Esta será una declaración única en algunos softwares matemáticos
2011

1
@ st0le: Correcto, y no se le permitiría usar dicha función en dichos sistemas. :-D
Chris Jester-Young

Respuestas:


2

Python 95 89

ces tu funcion Devuelve 0 si no hay inverso (es decir, cuando x es par).

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]

3

Python, 29 bytes

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

Esto devuelve 0 para incluso x . Utiliza el teorema de Euler, con la observación de que 2 ^ n - 1 es divisible por 2 ^ ( n - 1) - 1, a través de la exponenciación modular rápida incorporada de Python. Esto es lo suficientemente rápido para n hasta 7000 más o menos, donde comienza a tomar más de aproximadamente un segundo.


2

Mathematica - 22

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

f[x,n]vuelve ycon x*y=1 mod 2^n, de lo contrariox is not invertible modulo 2^n


2

GolfScript (23 caracteres)

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

El resultado centinela para un inverso inexistente es 0 .

Esta es una aplicación simple del teorema de Euler . , entonces x - 1x 2 n - 1 - 1xφ(2n)1(mod2n)x1x2n11(mod2n)

Desafortunadamente, es un exponencial demasiado grande para calcular directamente, por lo que tenemos que usar un bucle y hacer una reducción modular dentro del bucle. El paso iterativo es y tenemos una opción de caso base: ya sea conx2k1=(x2k11)2×xk=1

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

o k=2con

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

Estoy trabajando en otro enfoque, pero el centinela es más difícil.

La observación clave es que podemos construir el inverso hacia arriba poco a poco: si 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 es par.

Eso le da la función de 19 caracteres

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

xx&11

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

02n1 , pero aún no lo he probado.

01(x+1)n11n

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

nn x f

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

1

Ruby - 88 caracteres

Usa la función 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

Simplemente la función recursiva de la página wiki vinculada, devuelve 0 en caso de error.


Puede guardar algunos caracteres por inlining e: (e=->a,b{...})[x,2**n][0]. También puede guardar un personaje probando en a%b<1lugar de a%b==0.
histocrat


1

Pyth , 9 bytes

.^Et^2Q^2

Pruébalo aquí!

Toma la entrada en orden inverso. O, 9 bytes demasiado: .^EtK^2QK.

Explicación

. ^ Et ^ 2Q ^ 2 - Programa completo.

^ - Función Pow. Lo mismo en Python (pow).
  E - La segunda entrada.
    ^ 2Q - Y 2 ^ primera entrada.
   t - Disminuido.
       ^ 2 - Y 2 ^ primera entrada de nuevo.

0

GAP, 39 bytes

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

f(x,n)devuelve el inverso del xmódulo 2^ny muestra un mensaje de error

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

si no existe inversa

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.