En el sentido de muchos desafíos, pensé que este podría ser interesante.
En este desafío, utilizaremos el Sistema de número de residuos (RNS) para realizar sumas, restas y multiplicaciones en enteros grandes.
¿Qué es el RNS?
El RNS es una de las muchas formas en que las personas se han desarrollado para identificar enteros. En este sistema, los números están representados por una secuencia de residuos (que son los resultados después de una operación de módulo (es decir, el resto después de la división de enteros)). En este sistema, cada entero tiene muchas representaciones. Para mantener las cosas simples, vamos a limitar las cosas para que cada número entero esté representado de forma única. Creo que es más fácil describir lo que está sucediendo con un ejemplo concreto.
Veamos los primeros tres números primos: 2, 3, 5. En el sistema RNS, podemos usar estos tres números para representar de manera única cualquier número que sea menor que 2 * 3 * 5 = 30 usando residuos. Toma 21:
21 es menor que 30, por lo que podemos representarlo usando los resultados después de modificar por 2, 3 y 5. (es decir, el resto después de un entero dividiendo entre 2, 3 y 5)
Identificaríamos 21 con la siguiente secuencia de enteros:
21 ~ {21 mod 2, 21 mod 3, 21 mod 5} = {1, 0, 1}
Y así, en nuestro sistema RNS, en lugar de "21", usaríamos {1,0,1}.
En general, dado un número entero n , representamos n como { n mod 2, ..., n mod p_k } donde p_k es el primo más pequeño, de modo que n es menor que el producto de todos los primos menores o iguales que p_k .
Otro ejemplo, digamos que tenemos 3412. Necesitamos usar 2,3,5,7,11,13 aquí porque 2*3*5*7*11*13=30030
, mientras 2*3*5*7*11=2310
que , que es demasiado pequeño.
3412 ~ {3412 mod 2, 3412 mod 3, 3412, mod 5, ..., 3412 mod 13} = {0, 1, 2, 3, 2, 6}
Usted nota que usando este sistema podemos representar números muy grandes relativamente sin dolor. Usando {1, 2, 3, 4, 5, 6, 7, 8, ...} residuos, podemos representar números hasta {2, 6, 30, 210, 2310, 30030, 510510, 9699690 ...} respectivamente. ( Aquí está la serie )
Nuestra tarea
Utilizaremos estos residuos para realizar +, - y * en grandes cantidades. Describiré estos procesos a continuación. Por ahora, aquí están las especificaciones de entrada y salida.
Entrada
Se le darán dos números (potencialmente muy grandes) a través de un stdin o argumento de función. Se darán como cadenas de 10 dígitos de base.
Con el fin de delinear aún más el problema, llamamos a la primera entrada n
y a la segunda m
. Suponga que n> m> = 0 .
También se le dará +
o -
o *
para indicar la operación a realizar.
Salida
Deje x ser un número entero. Usaremos [ x ] para referirnos a la representación RNS descrita anteriormente de x .
Debes dar salida [n] <operator> [m] = [result]
Cómo realizar las operaciones en RNS
Estas operaciones son relativamente simples. Dados dos números en notación RNS, para sumarlos, restarlos o multiplicarlos, simplemente realice las operaciones dadas por componentes y luego tome el módulo.
es decir
{1, 2, 3} + {1, 1, 4} = {(1 + 1) mod 2, (2 + 1) mod 3, (3 + 4) mod 5} = {0, 0, 2}
Tenga en cuenta que si el número de residuos utilizado para representar dos números diferentes no es el mismo, al realizar operaciones, deberá extender el número "más corto" para que tenga el mismo número de residuos. Esto sigue el mismo proceso. Vea los casos de prueba para un ejemplo.
Lo mismo ocurre si el resultado requiere más residuos que cualquier entrada. Entonces ambas entradas necesitan ser "extendidas".
Detalles importantes
Aquí trataremos con grandes números, pero no arbitrariamente grandes. Seremos responsables de los números hasta el producto de los primeros 100 primos (ver más abajo). Para este fin, se le otorgan los primeros 100 primos gratis (sin costo de byte) . Puede pegarlos en una matriz llamada
p
o algo idiomático en su idioma y luego restar el número de bytes utilizados para iniciar esta matriz de su total final. Esto, por supuesto, significa que pueden estar codificados o puede usar uno incorporado para generarlos.Si por alguna razón esta es la representación entera por defecto utilizada en su idioma. Eso está bien.
No puede usar ningún tipo de Entero de precisión arbitraria a menos que sea el idioma predeterminado. Si es el valor predeterminado, no puede usarlo para almacenar enteros que normalmente no caben en 64 bits.
Para ser claros, cada número entero siempre estará representado con la menor cantidad de residuos posible. Esto se aplica tanto a la entrada como a la salida.
Creo que las otras especificaciones deberían evitar esto, pero ser redundantes: es posible que no realice la operación dada en las entradas y luego cambie todo a RNS y luego a la salida. Debe cambiar las entradas a RNS y luego realizar las operaciones para producir la salida.
Casos de prueba
Entrada:
n = 10
m = 4
+
Salida:
{ 0, 1, 0 } + { 0, 1 } = { 0, 2, 4 }
Explicación:
Primero, cambie cada número a su representación RNS como se describe arriba:
10 ~ {0,1,0}
y 4 ~ {0,1}
. Tenga en cuenta que cuando queremos hacer una suma de componentes, 10
tiene más componentes que 4
. Por lo tanto, debemos "extender" el número más corto. Entonces escribiremos brevemente 4 ~ {0,1} --> {0,1, 4 mod 5} = {0,1,4}
. Ahora procedemos con la suma y luego tomamos el módulo.
- Entrada
n=28
m=18
+
Salida:
[ 0, 1, 3 ] + [0, 0, 3 ] = [ 0, 1, 1, 4 ]
- Entrada (me aplasta la cara en el teclado)
n=1231725471982371298419823012819231982571923
m=1288488183
*
Salida (dividida en líneas separadas para facilitar la lectura):
[1, 2, 3, 6, 2, 10, 2, 1, 12, 16, 7, 15, 34, 29, 31, 5, 55, 32, 66, 61, 3, 76, 52, 14, 65, 44, 99, 57 ]
*
[1, 0, 3, 3, 4, 8, 9, 10, 8, 0 ]
=
[1, 0, 4, 4, 8, 2, 1, 10, 4, 0, 17, 7, 27, 21, 44, 51, 56, 9, 6, 9, 12, 0, 52, 36, 43, 68, 99, 24, 96, 39, 96, 66, 125]
n
requiere 28 primos. m
requiere 10. n*m
requiere 33.
- Entrada
n=8709668761379269784034173446876636639594408083936553641753483991897255703964943107588335040121154680170867105541177741204814011615930342030904704147856733048115934632145172739949220591246493529224396454328521288726490
m=1699412683745170450115957274739962577420086093042490863793456500767137147999161679589295549397604032154933975242548831536518655879433595016
-
Salida:
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 509]
-
[0, 2, 1, 6, 1, 12, 11, 18, 14, 28, 21, 36, 37, 42, 16, 52, 41, 60, 16, 70, 49, 78, 80, 88, 49, 100, 13, 106, 4, 112, 68, 130, 36, 138, 37, 150, 0, 162, 8, 172, 163, 180, 18, 192, 129, 198, 135, 222, 78, 228, 90, 238, 57, 250, 36, 262, 87, 270, 206, 280, 193, 292, 253, 310, 224, 316, 57, 336, 48, 348]
=
[0, 1, 4, 1, 10, 1, 6, 1, 9, 1, 10, 1, 4, 1, 31, 1, 18, 1, 51, 1, 24, 1, 3, 1, 48, 1, 90, 1, 105, 1, 59, 1, 101, 1, 112, 1, 0, 1, 159, 1, 16, 1, 173, 1, 68, 1, 76, 1, 149, 1, 143, 1, 184, 1, 221, 1, 182, 1, 71, 1, 90, 1, 54, 1, 89, 1, 274, 1, 299, 1, 266, 1, 228, 1, 340, 1, 170, 1, 107, 1, 340, 1, 88, 1, 157, 1, 143, 1, 22, 1, 22, 1, 58, 1, 296, 1, 371, 1, 140]
n
utiliza 100 primos m
usa 70 primos. n-m
usa 99 primos.
Lo verifiqué usando la ChineseRem
implementación incorporada del teorema del resto chino en GAP (que básicamente toma números RNS y los cambia a enteros de base 10). Creo que son correctos. Si algo parece sospechoso, hágamelo saber.
Para aquellos que se preocupan, el producto de los primeros 100 primos es:
471193079990618495316248783476026042202057477340967552018863483961641533584503
422120528925670554468197243910409777715799180438028421831503871944494399049257
9030720635990538452312528339864352999310398481791730017201031090
Este número es 1 mayor que el número máximo que podemos representar usando el sistema dado (y la limitación principal de 100).
(a,b,o)=>a.map((v,i)=>eval(v+o+b[i]))
en ES6 por ejemplo. Creo que la parte más difícil es probablemente encontrar el número de primos necesarios para representar el resultado sin usar aritmética de precisión arbitraria, aunque la conversión posterior a RNS no es exactamente trivial.
1234,1234,+
)?