Sie erhalten eine 16-Bit-Maschine und müssen die Multiplikation von Ganzzahlen beliebiger Größe implementieren. Ihre Register können nur 16-Bit-Zahlen enthalten, und der größte Multiplikationsbefehl verwendet zwei 8-Bit-Eingänge und generiert ein 16-Bit-Ergebnis.
Ihr Programm muss zwei positive Zahlen beliebiger Größe als Eingabe verwenden und deren Produkt ausgeben. Jede Eingangsnummer wird in einer eigenen Zeile als Little-Endian-Byte-Array codiert, wobei jedes Byte eine zweistellige Hex-Zahl ist. Die Ausgabe muss ähnlich formatiert sein. Vielleicht am besten mit einem Beispiel erklärt:
Eingang
1f 4a 07
63 a3
Ausgabe
fd 66 03 a7 04
Dies codiert die Multiplikation 477727 * 41827 = 19981887229.
Sie können davon ausgehen, dass das letzte (höchstwertige) Byte jeder Eingabenummer ungleich Null ist und der letzte Teil der von Ihnen ausgegebenen Nummer ungleich Null sein muss. Beide Eingabenummern sind höchstens 100 Byte lang.
Kleinster Code gewinnt.
Denken Sie daran, dass die größte Multiplikation, die Sie verwenden dürfen, 1 Byte * 1 Byte und keine Integer-Typen größer als 2 Byte ist!
Antworten:
Perl, 137 Zeichen
Vorbehalte
00
Byte am Ende des Ergebnisses aus. Natürlich ist das Ergebnis auch mit diesem zusätzlichen Byte noch korrekt.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:
Nun schreiben Sie neben die 13 die andere Zahl 47 und multiplizieren sie immer wieder mit 2:
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:
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 >> 1
und tuny << 1
. Darüber hinaus fügen wir diey
nur wennx & 1 == 1
. Dies übersetzt sich direkt in einen Algorithmus, den ich hier in Pseudocode schreiben werde: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: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:
$x
und$y
sind die Eingaben im Hex-Format, so dass sie das niedrigstwertige Byte zuerst haben .Also, anstelle von
x >> 8
mir$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 << 8
ist einfach$y = "00$y"
.Das
result
ist tatsächlich ein numerisches Array@r
. Am Ende@r
enthä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:
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
while
Schleife beweisen :Das
@r
Leerzeichen 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
@r
zu Beginn jederwhile
Iteration nur einzelne Bytes enthält :Die
for
Schleife 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
$x
und entfernen$y
:Daher
$e*hex
ist eine Multiplikation von zwei Einzelbyte-Werten, was bedeutet, es liegt im Bereich0 — 0xFE01
.Nach der induktiven Hypothese
$r[$i]
ist ein Byte; liegt daher$s = $r[$i] += $e*hex
im bereich0 — 0xFF00
.Daher
$s >> 8
ist immer ein Byte.$y
wächst ein Extra00
in jeder Iteration derwhile
Schleife:Daher wird in jeder Iteration der
while
Schleife die innerefor
Schleife eine Iteration länger ausgeführt als in der vorherigenwhile
Iteration.Daher addiert sich die
$r[++$i] += $s >> 8
in der letzten Iteration derfor
Schleife immer$s >> 8
zu0
, und wir haben bereits festgestellt, dass dies$s >> 8
immer ein Byte ist.Daher ist der letzte
@r
am Ende derfor
Schleife gespeicherte Wert auch ein einzelnes Byte.Dies schließt eine wunderbare und aufregende Herausforderung ab. Vielen Dank für die Veröffentlichung!
quelle
C Lösung
Diese Lösung führt keine Eingabevalidierung durch. Es ist auch nur wenig getestet. Geschwindigkeit war nicht wirklich eine Überlegung. Mallocs Gedächtnis, und es ist nicht besonders klug, wie viel es packt. Garantiert genug und mehr als nötig.
m () akzeptiert eine Zeichenfolge und erwartet zwei Zeilenumbrüche in der Zeichenfolge, einen nach jeder Zahl. Erwartet nur Zahlen, Kleinbuchstaben, Leerzeichen und Zeilenumbrüche. Erwartet, dass hexadezimale Ziffern immer ein Paar sind.
Es wird niemals (wissentlich) eine Multiplikationsoperation verwendet. Das Verschieben wird für 8-Bit-Variablen durchgeführt. Eine 16-Bit-Addition wird durchgeführt. Keine 32-Bit-Datentypen.
Von Hand geschrumpft und nur leicht. edit: mehr Verschleierung, weniger Zeichen: D Kompiliert mit Warnungen mit gcc.
Zeichen: 675
Sie können damit testen:
Ergebnis:
quelle
OCaml + Batterien, 362 Zeichen
Ein standardmäßiger O (n * m) Schüler-Multiplikationsalgorithmus. Beachten Sie, dass zur Erfüllung der Herausforderungsanforderungen die Operationen an den Bytes von Zeichenfolgen ausgeführt werden, die in OCaml (in diesem Fall günstigerweise) veränderbar sind. Es ist auch zu beachten, dass der Akkumulator
s
niemals 16 Bits überläuft, da 2 (2 ^ 8 - 1) + (2 ^ 8 - 1) ^ 2 = (2 ^ 8 - 1) (2 ^ 8 + 1) = 2 ^ 16 - 1 .Beispielsweise,
quelle
JavaScript (Node.js) , 160 Byte
Probieren Sie es online!
Viel neuere Sprache als damals
quelle