Perl, 137 Zeichen
($x,$y)=<>;while($x=~s/.. *//s){$e=hex$&;$i=0;$s=$r[$i]+=$e*hex,$r[$i]&=255,$r[++$i]+=$s>>8 for$y=~/.. */gs;$y="00$y"}printf'%02x 'x@r,@r
Vorbehalte
- Druckt manchmal ein Extra
00 Byte am Ende des Ergebnisses aus. Natürlich ist das Ergebnis auch mit diesem zusätzlichen Byte noch korrekt.
- Gibt nach dem letzten Hex-Byte im Ergebnis ein zusätzliches Leerzeichen aus.
Erläuterung
Die Erklärung wird ein bisschen lang sein, aber ich denke, die meisten Leute hier werden es interessant finden.
Als ich 10 Jahre alt war, wurde mir zunächst der folgende kleine Trick beigebracht. Sie können damit zwei beliebige positive Zahlen multiplizieren. Ich beschreibe dies am Beispiel von 13 × 47. Sie schreiben zunächst die erste Zahl 13 und dividieren sie durch 2 (jeweils abrunden), bis Sie 1 erreichen:
13
6
3
1
Nun schreiben Sie neben die 13 die andere Zahl 47 und multiplizieren sie immer wieder mit 2:
13 47
6 94
3 188
1 376
Nun findet man alle Linien kreuzen, wo die Zahl auf der linken Seite ist sogar . In diesem Fall ist dies nur die 6. (Ich kann den Code nicht durchstreichen, daher entferne ich ihn einfach.) Zum Schluss fügen Sie alle verbleibenden Zahlen rechts hinzu:
13 47
3 188
1 376
----
611
Und das ist die richtige Antwort. 13 × 47 = 611.
Jetzt, da Sie alle Computerfreaks sind, haben Sie gemerkt, dass wir in der linken und rechten Spalte jeweils x >> 1und tun y << 1. Darüber hinaus fügen wir die ynur wenn x & 1 == 1. Dies übersetzt sich direkt in einen Algorithmus, den ich hier in Pseudocode schreiben werde:
input x, y
result = 0
while x > 0:
if x & 1 == 1:
result = result + y
x = x >> 1
y = y << 1
print result
Wir können das umschreiben if, um eine Multiplikation zu verwenden, und dann können wir dies einfach so ändern, dass es byteweise statt bitweise funktioniert:
input x, y
result = 0
while x > 0:
result = result + (y * (x & 255))
x = x >> 8
y = y << 8
print result
Dies enthält immer noch eine Multiplikation mit y, die eine beliebige Größe hat, also müssen wir diese auch in eine Schleife umwandeln. Das machen wir in Perl.
Übersetzen Sie jetzt alles in Perl:
$xund $ysind die Eingaben im Hex-Format, so dass sie das niedrigstwertige Byte zuerst haben .
Also, anstelle von x >> 8mir $x =~ s/.. *//s. Ich brauche das Leerzeichen + Stern, weil das letzte Byte möglicherweise kein Leerzeichen enthält (könnte auch Leerzeichen + verwenden ?). Dadurch wird das entfernte Byte ( x & 255) automatisch in eingefügt $&.
y << 8ist einfach $y = "00$y".
Das resultist tatsächlich ein numerisches Array @r. Am Ende @renthält jedes Element von ein Byte der Antwort, aber nach der Hälfte der Berechnung kann es mehr als ein Byte enthalten. Ich werde Ihnen im Folgenden beweisen, dass jeder Wert niemals mehr als zwei Bytes (16 Bits) beträgt und dass das Ergebnis immer ein Byte am Ende ist.
Also hier ist der Perl-Code entschlüsselt und kommentiert:
# Input x and y
($x, $y) = <>;
# Do the equivalent of $& = x & 255, x = x >> 8
while ($x =~ s/.. *//s)
{
# Let e = x & 255
$e = hex $&;
# For every byte in y... (notice this sets $_ to each byte)
$i = 0;
for ($y =~ /.. */gs)
{
# Do the multiplication of two single-byte values.
$s = $r[$i] += $e*hex,
# Truncate the value in $r[$i] to one byte. The rest of it is still in $s
$r[$i] &= 255,
# Move to the next array item and add the carry there.
$r[++$i] += $s >> 8
}
# Do the equivalent of y = y << 8
$y = "00$y"
}
# Output the result in hex format.
printf '%02x ' x @r, @r
Nun zum Beweis, dass dies immer Bytes ausgibt und die Berechnung niemals Werte erzeugt, die größer als zwei Bytes sind. Ich werde dies durch Induktion über die whileSchleife beweisen :
Das @rLeerzeichen am Anfang enthält eindeutig keine Werte größer als 0xFF (da es überhaupt keine Werte enthält). Damit ist der Basisfall abgeschlossen.
Nun, da dies @rzu Beginn jeder whileIteration nur einzelne Bytes enthält :
Die forSchleife enthält explizit &=alle Werte im Ergebnis-Array mit 255, mit Ausnahme des letzten. Wir müssen uns also nur diesen letzten ansehen.
Wir wissen, dass wir immer nur ein Byte von $xund entfernen $y:
Daher $e*hexist eine Multiplikation von zwei Einzelbyte-Werten, was bedeutet, es liegt im Bereich 0 — 0xFE01.
Nach der induktiven Hypothese $r[$i]ist ein Byte; liegt daher $s = $r[$i] += $e*hexim bereich 0 — 0xFF00.
Daher $s >> 8ist immer ein Byte.
$ywächst ein Extra 00in jeder Iteration der whileSchleife:
Daher wird in jeder Iteration der whileSchleife die innere forSchleife eine Iteration länger ausgeführt als in der vorherigen whileIteration.
Daher addiert sich die $r[++$i] += $s >> 8in der letzten Iteration der forSchleife immer $s >> 8zu 0, und wir haben bereits festgestellt, dass dies $s >> 8immer ein Byte ist.
Daher ist der letzte @ram Ende der forSchleife gespeicherte Wert auch ein einzelnes Byte.
Dies schließt eine wunderbare und aufregende Herausforderung ab. Vielen Dank für die Veröffentlichung!