Le dan una máquina de 16 bits y le dicen que implemente la multiplicación de enteros de tamaño arbitrario. Sus registros solo pueden contener números de 16 bits, y la instrucción de multiplicación más grande toma dos entradas de 8 bits y genera un resultado de 16 bits.
Su programa debe tomar como entrada dos números positivos de tamaño arbitrario y generar su producto. Cada número de entrada se codifica en su propia línea como una matriz de bytes little endian donde cada byte es un número hexadecimal de 2 dígitos. La salida debe tener un formato similar. Quizás mejor explicado con un ejemplo:
entrada
1f 4a 07
63 a3
salida
fd 66 03 a7 04
que codifica la multiplicación 477727 * 41827 = 19981887229.
Puede suponer que el último byte (el más significativo) de cada número de entrada es distinto de cero, y el último fragmento del número que genera debe ser distinto de cero. Ambos números de entrada tendrán como máximo 100 bytes de longitud.
El código más pequeño gana.
Recuerde, la multiplicación más grande que puede usar es 1 byte * 1 byte, ¡y no hay tipos enteros de más de 2 bytes!
Respuestas:
Perl, 137 caracteres
Advertencias
00
byte adicional al final del resultado. Por supuesto, el resultado sigue siendo correcto incluso con ese byte adicional.Explicación
La explicación va a ser un poco larga, pero creo que la mayoría de la gente aquí la encontrará interesante.
En primer lugar, cuando tenía 10 años, me enseñaron el siguiente truco. Puedes multiplicar dos números positivos con esto. Describiré esto usando el ejemplo de 13 × 47. Comienzas escribiendo el primer número, 13, y dividiéndolo entre 2 (redondeando hacia abajo cada vez) hasta llegar a 1:
Ahora, al lado del 13, escribe el otro número, 47, y sigue multiplicándolo por 2 la misma cantidad de veces:
Ahora tachas todas las líneas donde el número de la izquierda es par . En este caso, esto es solo el 6. (No puedo hacer tachado en el código, así que lo eliminaré). Finalmente, agrega todos los números restantes a la derecha:
Y esta es la respuesta correcta. 13 × 47 = 611.
Ahora, como todos ustedes son geeks de la computadora, se habrán dado cuenta de que lo que realmente estamos haciendo en las columnas izquierda y derecha es
x >> 1
yy << 1
, respectivamente. Además, agregamos ely
único six & 1 == 1
. Esto se traduce directamente en un algoritmo, que escribiré aquí en pseudocódigo:Podemos volver a escribir el
if
para usar una multiplicación, y luego podemos cambiar esto fácilmente para que funcione byte a byte en lugar de bit a bit:Esto todavía contiene una multiplicación con
y
, que es de tamaño arbitrario, por lo que también debemos cambiar eso en un ciclo. Lo haremos en Perl.Ahora traduzca todo a Perl:
$x
y$y
son las entradas en formato hexadecimal, por lo que primero tienen el byte menos significativo .Por lo tanto, en lugar de lo
x >> 8
que hago$x =~ s/.. *//s
. Necesito el espacio + estrella porque el último byte podría no tener espacio (también podría usar espacio +?
). Esto coloca automáticamente el byte eliminado (x & 255
) en$&
.y << 8
es simplemente$y = "00$y"
.La
result
realidad es una matriz numérica,@r
. Al final, cada elemento@r
contiene un byte de la respuesta, pero a la mitad del cálculo puede contener más de un byte. Te demostraré a continuación que cada valor nunca tiene más de dos bytes (16 bits) y que el resultado es siempre un byte al final.Así que aquí está el código Perl descifrado y comentado:
Ahora para la prueba de que esto siempre genera bytes , y que el cálculo nunca genera valores superiores a dos bytes. Lo probaré por inducción sobre el
while
bucle:El vacío
@r
al principio claramente no tiene valores mayores que 0xFF (porque no tiene valores en absoluto). Esto concluye el caso base.Ahora, dado que
@r
contiene solo bytes individuales al comienzo de cadawhile
iteración:El
for
bucle explícitamente&=
muestra todos los valores en la matriz de resultados con 255 excepto el último , por lo que solo tenemos que mirar ese último.Sabemos que siempre eliminamos solo un byte
$x
y$y
:Por lo tanto,
$e*hex
es una multiplicación de dos valores de un solo byte, lo que significa que está en el rango0 — 0xFE01
.Por la hipótesis inductiva,
$r[$i]
es un byte; por lo tanto,$s = $r[$i] += $e*hex
está en el rango0 — 0xFF00
.Por lo tanto,
$s >> 8
siempre es un byte.$y
crece un extra00
en cada iteración delwhile
bucle:Por lo tanto, en cada iteración del
while
ciclo, elfor
ciclo interno se ejecuta por una iteración más que en lawhile
iteración anterior .Por lo tanto,
$r[++$i] += $s >> 8
en la última iteración delfor
bucle siempre se agrega$s >> 8
a0
, y ya establecimos que$s >> 8
siempre es un byte.Por lo tanto, el último valor almacenado
@r
al final delfor
ciclo también es un solo byte.Esto concluye un desafío maravilloso y emocionante. ¡Muchas gracias por publicarlo!
fuente
Solución C
Esta solución no valida la entrada. También es solo ligeramente probado. La velocidad no era realmente una consideración. La memoria de Malloc, y no es particularmente inteligente sobre cuánto agarra. Garantizado para ser suficiente y más de lo necesario.
m () acepta una cadena, espera dos nuevas líneas en la cadena, una después de cada número. Solo espera números, caracteres en minúscula, espacios y líneas nuevas. Espera que los dígitos hexadecimales sean siempre un par.
No se utiliza ninguna operación de multiplicación (a sabiendas). El cambio se realiza en variables de 8 bits. Se realiza una adición de 16 bits. No hay tipos de datos de 32 bits.
Encogido a mano, y solo levemente. editar: más ofuscación, menos caracteres: D Compila con advertencias con gcc.
Caracteres: 675
Puedes probar con esto:
Resultado:
fuente
OCaml + Batteries, 362 caracteres
Un algoritmo estándar de multiplicación de colegial O (n * m). Tenga en cuenta que para cumplir con los requisitos de desafío, las operaciones se realizan en los bytes de las cadenas, que en OCaml son (convenientemente, en este caso) mutables. Tenga en cuenta también que el acumulador
s
nunca desborda 16 bits, ya que 2 (2 ^ 8 - 1) + (2 ^ 8 - 1) ^ 2 = (2 ^ 8 - 1) (2 ^ 8 + 1) = 2 ^ 16 - 1 .Por ejemplo,
fuente
JavaScript (Node.js) , 160 bytes
Pruébalo en línea!
Lenguaje mucho más nuevo que ese tiempo
fuente