On vous donne une machine 16 bits et on vous dit d'implémenter la multiplication d'entiers de taille arbitraire. Vos registres ne peuvent contenir que des nombres 16 bits, et la plus grande instruction de multiplication prend deux entrées 8 bits et génère un résultat 16 bits.
Votre programme doit prendre en entrée deux nombres positifs de taille arbitraire et sortir leur produit. Chaque numéro d'entrée est codé sur sa propre ligne comme un tableau d'octets petit-boutien où chaque octet est un nombre hexadécimal à 2 chiffres. La sortie doit être formatée de manière similaire. Peut-être mieux expliqué avec un exemple:
contribution
1f 4a 07
63 a3
production
fd 66 03 a7 04
qui code pour la multiplication 477727 * 41827 = 19981887229.
Vous pouvez supposer que le dernier octet (le plus significatif) de chaque numéro d'entrée est différent de zéro et que le dernier bloc du nombre que vous avez sorti doit être différent de zéro. Les deux numéros d'entrée auront une longueur maximale de 100 octets.
Le plus petit code gagne.
Rappelez-vous, la plus grande multiplication que vous êtes autorisé à utiliser est de 1 octet * 1 octet, et aucun type entier supérieur à 2 octets!
Réponses:
Perl, 137 caractères
Avertissements
00
octet supplémentaire à la fin du résultat. Bien sûr, le résultat est toujours correct, même avec cet octet supplémentaire.Explication
L'explication va être un peu longue, mais je pense que la plupart des gens ici trouveront cela intéressant.
Tout d'abord, quand j'avais 10 ans, on m'a appris le petit truc suivant. Vous pouvez multiplier deux nombres positifs avec ceci. Je vais décrire cela en utilisant l'exemple de 13 × 47. Vous commencez par écrire le premier nombre, 13, et en le divisant par 2 (arrondir à chaque fois) jusqu'à ce que vous atteigniez 1:
Maintenant, à côté du 13, vous écrivez l'autre nombre, 47, et continuez à le multiplier par 2 le même nombre de fois:
Maintenant, vous biffez toutes les lignes où le nombre sur la gauche est pair . Dans ce cas, ce n'est que le 6. (Je ne peux pas barrer dans le code, donc je vais juste le supprimer.) Enfin, vous ajoutez tous les chiffres restants à droite:
Et c'est la bonne réponse. 13 × 47 = 611.
Maintenant, puisque vous êtes tous des geeks informatiques, vous aurez réalisé que ce que nous faisons réellement dans les colonnes de gauche et de droite est
x >> 1
ety << 1
, respectivement. De plus, nous ajoutons ley
seul ifx & 1 == 1
. Cela se traduit directement par un algorithme, que j'écrirai ici en pseudocode:Nous pouvons réécrire le
if
pour utiliser une multiplication, puis nous pouvons facilement le changer pour qu'il fonctionne octet par octet au lieu de bit par bit:Cela contient toujours une multiplication avec
y
, qui est de taille arbitraire, nous devons donc aussi changer cela en boucle. Nous le ferons en Perl.Maintenant, traduisez tout en Perl:
$x
et$y
sont les entrées au format hexadécimal, donc elles ont d' abord l' octet le moins significatif .Ainsi, au lieu de
x >> 8
moi$x =~ s/.. *//s
. J'ai besoin de l'espace + étoile parce que le dernier octet pourrait ne pas avoir d'espace (pourrait utiliser l'espace +?
aussi). Cela place automatiquement l'octet supprimé (x & 255
) dans$&
.y << 8
est tout simplement$y = "00$y"
.Le
result
est en fait un tableau numérique,@r
. À la fin, chaque élément de@r
contient un octet de la réponse, mais à mi-chemin du calcul, il peut contenir plus d'un octet. Je vais vous prouver ci-dessous que chaque valeur ne dépasse jamais deux octets (16 bits) et que le résultat est toujours un octet à la fin.Voici donc le code Perl démêlé et commenté:
Maintenant, pour la preuve que cela génère toujours des octets et que le calcul ne génère jamais de valeurs supérieures à deux octets. Je vais le prouver par induction sur la
while
boucle:Le vide
@r
au début n'a clairement aucune valeur supérieure à 0xFF (car il ne contient aucune valeur). Ceci conclut le scénario de base.Maintenant, étant donné qu'il
@r
ne contient que des octets uniques au début de chaquewhile
itération:La
for
boucle contient explicitement&=
toutes les valeurs du tableau de résultats avec 255 sauf la dernière , nous n'avons donc qu'à regarder cette dernière.Nous savons que nous supprimons toujours un seul octet
$x
et$y
:Par conséquent,
$e*hex
est une multiplication de deux valeurs à un octet, ce qui signifie qu'il est dans la plage0 — 0xFE01
.Par l'hypothèse inductive,
$r[$i]
est un octet; est donc$s = $r[$i] += $e*hex
dans la plage0 — 0xFF00
.Par conséquent,
$s >> 8
est toujours un octet.$y
augmente de plus00
à chaque itération de lawhile
boucle:Par conséquent, à chaque itération de la
while
boucle, lafor
boucle interne s'exécute pour une itération de plus que lors de l'while
itération précédente .Par conséquent, la
$r[++$i] += $s >> 8
dans la dernière itération de lafor
boucle ajoute toujours$s >> 8
à0
, et nous avons déjà établi que$s >> 8
est toujours un octet.Par conséquent, la dernière valeur stockée
@r
à la fin de lafor
boucle est également un octet unique.Ceci conclut un défi merveilleux et passionnant. Merci beaucoup de l'avoir posté!
la source
Solution C
Cette solution ne fait aucune validation d'entrée. Il n'est également que légèrement testé. La vitesse n'était pas vraiment une considération. La mémoire de Malloc, et n'est pas particulièrement intelligent sur combien il saisit. Garanti suffisant et plus que nécessaire.
m () accepte une chaîne, attend deux sauts de ligne dans la chaîne, un après chaque numéro. N'attend que des chiffres, des minuscules, des espaces et des retours à la ligne. S'attend à ce que les chiffres hexadécimaux soient toujours une paire.
Aucune opération de multiplication n'est jamais utilisée (sciemment). Le décalage est effectué sur des variables 8 bits. Un ajout de 16 bits est effectué. Aucun type de données 32 bits.
Rétréci à la main, et seulement légèrement. edit: plus d'obscurcissement, moins de caractères: D Compile avec des avertissements avec gcc.
Caractères: 675
Vous pouvez tester avec ceci:
Résultat:
la source
OCaml + Batteries, 362 caractères
Un algorithme de multiplication d'écolier standard O (n * m). Notez que pour répondre aux exigences du défi, les opérations sont effectuées sur les octets de chaînes qui, dans OCaml, sont (commodément, dans ce cas) mutables. Notez également que l'accumulateur
s
ne déborde jamais de 16 bits, car 2 (2 ^ 8 - 1) + (2 ^ 8 - 1) ^ 2 = (2 ^ 8 - 1) (2 ^ 8 + 1) = 2 ^ 16 - 1 .Par exemple,
la source
JavaScript (Node.js) , 160 octets
Essayez-le en ligne!
Beaucoup plus récent que cette époque
la source