Você recebe uma máquina de 16 bits e é instruído a implementar a multiplicação de números inteiros de tamanho arbitrário. Seus registros podem conter apenas números de 16 bits, e a maior instrução de multiplicação usa duas entradas de 8 bits e gera um resultado de 16 bits.
Seu programa deve tomar como entrada dois números positivos de tamanho arbitrário e gerar o produto deles. Cada número de entrada é codificado em sua própria linha como uma matriz de bytes little-endian, em que cada byte é um número hexadecimal de 2 dígitos. A saída deve ser formatada de maneira semelhante. Talvez seja melhor explicado com um exemplo:
entrada
1f 4a 07
63 a3
resultado
fd 66 03 a7 04
que codifica a multiplicação 477727 * 41827 = 19981887229.
Você pode assumir que o último byte (mais significativo) de cada número de entrada é diferente de zero, e o último pedaço do número que você produz deve ser diferente de zero. Os dois números de entrada terão no máximo 100 bytes.
O menor código vence.
Lembre-se, a maior multiplicação que você tem permissão para usar é 1 byte * 1 byte, e nenhum tipo inteiro maior que 2 bytes!
Respostas:
Perl, 137 caracteres
Ressalvas
00
byte extra no final do resultado. Obviamente, o resultado ainda está correto, mesmo com esse byte extra.Explicação
A explicação será um pouco longa, mas acho que a maioria das pessoas aqui achará interessante.
Antes de mais, quando eu tinha 10 anos, aprendi o pequeno truque a seguir. Você pode multiplicar quaisquer dois números positivos com isso. Descreverei isso usando o exemplo de 13 × 47. Comece escrevendo o primeiro número, 13 e dividindo -o por 2 (arredondar para baixo a cada vez) até chegar a 1:
Agora, ao lado dos 13, você escreve o outro número, 47, e continua multiplicando -o por 2 o mesmo número de vezes:
Agora você cruza todas as linhas em que o número à esquerda é par . Nesse caso, esse é apenas o 6. (Não consigo executar o código de correção, então vou removê-lo.) Finalmente, você adiciona todos os números restantes à direita:
E esta é a resposta certa. 13 × 47 = 611.
Agora, como todos vocês são viciados em computadores, perceberão que o que realmente estamos fazendo nas colunas esquerda e direita é
x >> 1
ey << 1
, respectivamente. Além disso, adicionamos oy
único sex & 1 == 1
. Isso se traduz diretamente em um algoritmo, que escreverei aqui no pseudocódigo:Podemos reescrever o
if
para usar uma multiplicação e, em seguida, podemos mudar isso facilmente para que funcione de byte a byte em vez de pouco a pouco:Isso ainda contém uma multiplicação com
y
tamanho arbitrário, portanto, também precisamos mudar isso para um loop. Nós vamos fazer isso em Perl.Agora traduza tudo para o Perl:
$x
e$y
são as entradas no formato hexadecimal, para que tenham primeiro o byte menos significativo .Assim, em vez de
x >> 8
eu faço$x =~ s/.. *//s
. Eu preciso do espaço + estrela porque o último byte pode não ter espaço nele (também pode usar espaço +?
). Isso coloca automaticamente o byte removido (x & 255
) em$&
.y << 8
é simplesmente$y = "00$y"
.O
result
é realmente uma matriz numérica@r
,. No final, cada elemento de@r
contém um byte da resposta, mas, no meio do cálculo, pode conter mais de um byte. Vou provar a você abaixo que cada valor nunca é superior a dois bytes (16 bits) e que o resultado é sempre um byte no final.Então, aqui está o código Perl desvendado e comentado:
Agora, a prova de que isso sempre gera bytes e que o cálculo nunca gera valores maiores que dois bytes. Vou provar isso por indução ao longo do
while
loop:O vazio
@r
no início claramente não possui valores maiores que 0xFF (porque não possui valores). Isso conclui o caso base.Agora, dado que
@r
contém apenas bytes únicos no início de cadawhile
iteração:O
for
loop explicitamente&=
s todos os valores na matriz de resultados com 255, exceto o último , portanto, precisamos apenas olhar para esse último.Sabemos que sempre removemos apenas um byte
$x
e$y
:Portanto,
$e*hex
é uma multiplicação de dois valores de byte único, o que significa que está no intervalo0 — 0xFE01
.Pela hipótese indutiva,
$r[$i]
é um byte; portanto,$s = $r[$i] += $e*hex
está no intervalo0 — 0xFF00
.Portanto,
$s >> 8
é sempre um byte.$y
cresce um extra00
em cada iteração dowhile
loop:Portanto, em todas as iterações do
while
loop, ofor
loop interno é executado por mais uma iteração do que nawhile
iteração anterior .Portanto, o
$r[++$i] += $s >> 8
na última iteração dofor
loop de sempre adiciona$s >> 8
a0
, e já estabeleceu que$s >> 8
é sempre um byte.Portanto, o último valor armazenado no
@r
final dofor
loop também é um único byte.Isso conclui um desafio maravilhoso e emocionante. Muito obrigado por publicá-lo!
fonte
Solução C
Esta solução não faz validação de entrada. Também é apenas levemente testado. Velocidade não era realmente uma consideração. A memória de Malloc, e não é particularmente inteligente sobre o quanto ela agarra. Garantido o suficiente e mais do que o necessário.
m () aceita uma string, espera duas novas linhas na string, uma após cada número. Espera apenas números, caracteres minúsculos, espaços e novas linhas. Espera que os dígitos hexadecimais sejam sempre um par.
Nenhuma operação de multiplicação é usada (conscientemente). A troca é realizada em variáveis de 8 bits. Uma adição de 16 bits é realizada. Não há tipos de dados de 32 bits.
Encolhido à mão, e apenas levemente. edit: mais ofuscação, menos caracteres: D Compila com avisos com o gcc.
Personagens: 675
Você pode testar com isso:
Resultado:
fonte
OCaml + Baterias, 362 caracteres
Um algoritmo de multiplicação de aluno O (n * m) padrão. Observe que, para atender aos requisitos de desafio, as operações são realizadas nos bytes de strings, que no OCaml são (convenientemente, neste caso) mutáveis. Observe também que o acumulador
s
nunca excede 16 bits, pois 2 (2 ^ 8 - 1) + (2 ^ 8 - 1) ^ 2 = (2 ^ 8 - 1) (2 ^ 8 + 1) = 2 ^ 16 - 1 .Por exemplo,
fonte
JavaScript (Node.js) , 160 bytes
Experimente online!
Idioma muito mais recente que o da época
fonte