Collatz-Sequenz auf einer Zwei-Zähler-Maschine

8

Die Collatz-Sequenz ausgehend von einer positiven ganzen Zahl n wird folgendermaßen definiert:

  • wenn n gerade ist, dann dividiere es durch 2 ( n' = n / 2)
  • Wenn n ungerade ist, multipliziere es mit 3 und addiere 1 ( n' = 3n + 1)

Wiederholen Sie die obige Iteration, bis n 1 erreicht.

Es ist nicht bekannt (es ist ein großes ungelöstes Problem in der Zahlentheorie), ob die Sequenz schließlich die Zahl 1 erreicht, unabhängig davon, welche positive ganze Zahl anfänglich gewählt wird.

Eine Zwei-Zähler-Maschine (2CM) ist eine Maschine, die mit zwei Registern ausgestattet ist, die einen nicht negativen ganzzahligen Wert enthalten können und mit dem folgenden Befehlssatz programmiert werden können:

INCX    increase the value of register X
INCY    increase the value of register Y
JMP n   jump to instruction n
DJZX n  if register X is zero jump to instruction n,
        otherwise decrement its value
DJZY n  if register Y is zero jump to instruction n,
        otherwise decrement its value
HALT    halt (and accept)
PRINTX  print the content of register X

Ein 2CM-Programm ist einfach eine Folge von Anweisungen. Beispielsweise kopiert das folgende Programm einfach den Inhalt von Register X in Register Y:

cp:   DJZX end
      INCY
      JMP cp
end:  HALT

Beachten Sie, dass ein 2CM Turing Complete ist (dh es kann jede berechenbare Funktion mit einer geeigneten Eingabecodierung berechnen, dies ist hier jedoch irrelevant). Beachten Sie auch, dass sich der Befehlssatz ein wenig von dem im Wikipedia-Artikel unterscheidet.

Die Herausforderung

Schreiben Sie das kürzeste 2CM-Programm, das die Collatz-Sequenz bis zu 1 berechnet und druckt und anhält (das Register X enthält anfänglich den Startwert nund das Register Y enthält anfänglich 0). Beachten Sie, dass die Länge eines 2CM-Programms der Anzahl der verwendeten Anweisungen entspricht (nicht der Länge des Textes).

Wenn beispielsweise von X = 3 aus gestartet wird, muss 3 10 5 16 8 4 2 1Folgendes gedruckt werden: und HALT.

Sie können also Ihre Lieblingssprache verwenden, um einen 2CM-Simulator / Interpreter zu erstellen. Der endgültige (kürzeste) Code, den Sie in die Antwort eingeben, muss jedoch in der 2CM-Sprache vorliegen .

Marzio De Biasi
quelle
Welches Programm sollen wir für die 2CM-Maschine schreiben?
FUZxxl
Muss Ihr Programm in HALT enden oder können Sie auch die Ausführung am Ende ablaufen lassen?
Orlp
1
@ LegionMammal978 spielt für die Codegröße keine Rolle.
FUZxxl
3
@MarzioDeBiasi Angesichts all dieser Kommentare empfehle ich die Sandbox (zumindest für Ihre nächste Herausforderung). Klare Herausforderungen zu schreiben ist schwierig, und selbst wenn Sie der Meinung sind, dass Sie alles geklärt haben, gibt es häufig offene Fragen für andere Benutzer, auf die in der Sandbox hingewiesen und eingegangen werden kann, bevor Sie die Herausforderung auf main veröffentlichen und die Leute mit der Arbeit beginnen es.
Martin Ender

Antworten:

11

18 Anweisungen

Ich war ein bisschen enttäuscht, dass ich spät vor Ort ankam, da die minimalistische Natur des Problems und die Sprache dort (scheinbar) nur einen allgemeinen Ansatz für eine gute Antwort liefern. Ich bekam ziemlich schnell eine Antwort mit 19 Anweisungen, aber ich hatte nicht das Gefühl, dass sie genug auf den Tisch brachte, um sie zu veröffentlichen. Aber nach langem Kopfkratzen kam meine Erfahrung mit der Hacky-Z80-Montage zum Tragen und ich fand einen Weg, eine Anweisung zu speichern, indem ich einen Codeblock für einen Zweck wiederverwendete, für den er nicht gedacht war!

# Let N be the previous number in the Collatz sequence.

# Print N, and if N==1, halt.
# X=N, Y=0
Main:           PRINTX          # Print N.
                DJZX Done       # X=N-1 (N shouldn't be zero, so this never jumps)
                DJZX Done       # If N-1==0, halt. Otherwise, X=N-2.

# Find the parity of N and jump to the proper code to generate the next N.
# X=N-2, Y=0
FindParity:     INCY
                DJZX EvenNext   # If N%2==0, go to EvenNext with X=0, Y=N-1.
                INCY
                DJZX OddNext    # If N%2==1, go to OddNext with X=0, Y=N-1.
                JMP FindParity

# Find the next N, given that the previous N is even.
# X=0, Y=N-1
EvenNext:       INCX
                DJZY Main       # Y=Y-1 (Y should be odd, so this never jumps)
                DJZY Main       # If Y==0, go to Main with X=(Y+1)/2=N/2, Y=0.
                JMP EvenNext

# Find the next N, given that the previous N is odd.
# X=0, Y=N-1
OddNext:        INCX
                INCX
                INCX
                DJZY EvenNext   # If Y==0, go to EvenNext with X=(Y+1)*3=N*3, Y=0.
                JMP OddNext     # ^ Abuses EvenNext to do the final INCX so X=N*3+1.

# Halt.
Done:           HALT
Runer112
quelle
1
Ich hoffe mein Dolmetscher hat nicht schlecht gesaugt: P Schöne Lösung.
Orlp
1
@orlp Hat wie ein Zauber funktioniert. Vielen Dank. :) :)
Runer112
1
Ihre Lösung gefällt mir sehr gut! Sehr schöner Missbrauch von EvenNext :)
Nejc
4

SCORE: 21

Hier ist mein Versuch:

main: druckt Xund springt zu finish(wenn X==1).

divisibility: unterscheidet, ob X%2==0oderX%2==1 . Kopiert Xauch Yund macht X==0. Springt entweder zu isDivisible(wenn X%2==0) oder isNotDivisible(wenn X%2==1).

isDivisible: Schleife verwendet, wenn Y%2==0. Bei jeder Abnahme Yum 2 erhöht sie sich Xum 1. Wenn Y==0, springt zu main.

isNotDivisible: verwendet wenn Y%2==1. Es erhöht sich Xum 1.

notDivLoop: Schleife verwendet, wenn Y%2==1 . Bei jeder Verringerung Yum 1 erhöht sie sich Xum 3. Wann Y==0springt zu main.

finish: hält an

main:           PRINTX              # print X
                DJZX main           # here X is always >0 and jump never fires (it is just for decreasing)
                DJZX finish         # if initially X==1 this jumps to finish
                INCX                # establish the previous state of X
                INCX
                                    # continue with X>1

divisibility:   DJZX isDivisible    # if X%2==0, then this will fire (when jumping Y=X)
                INCY
                DJZX isNotDivisible # if X%2==1, this fires (when jumping Y=X)
                INCY
                JMP divisibility    # jump to the beginning of loop

isDivisible:    DJZY main           # this jumps to the main loop with X=X/2
                DJZY main           # this jump will never fire, because X%2==0
                INCX                # for every partition 2 of Y, increase X (making X=Y/2)
                JMP isDivisible     # jump to beginning of loop

isNotDivisible: INCX                # X=0, increase for 1
notDivLoop:     DJZY main           # in each iteration, increase X for 3 (when Y==0, X=3Y+1)
                INCX
                INCX
                INCX
                JMP notDivLoop      # jump to beginning of loop

finish:         HALT                # finally halt

Mit 3 geliefert (unter Verwendung des von @orlp bereitgestellten Interpreters) ergibt sich Folgendes:

3
10 
5 
16 
8
4
2
1
Nejc
quelle
4

19 Anweisungen

Ich habe meinen eigenen Dolmetscher geschrieben, weil ich so Lust habe. Hier ist meine Lösung für meinen eigenen Dolmetscher:

MP
 XE
 XE
HY
 XV
 XO
 JH
WX
VYM
 JW
LYM
 X
 X
OX
 X
 X
 X
 JL
EH

Und so sieht es mit einer Syntax aus, die mit dem anderen Interpreter kompatibel ist:

# x = n, y = 0
main:    printx
         djzx   end
         djzx   end

# x = n - 2, y = 0 on fallthrough
half:    incy
         djzx   even
         djzx   odd
         jmp    half

evloop:  incx
# x = 0, y = n / 2  on jump to even
even:    djzy   main
         jmp    evloop

oddloop: djzy   main
         incx
         incx
# x = 0, y = (n + 1) / 2 on jump to even
odd:     incx
         incx
         incx
         incx
         jmp    oddloop

end:     halt
FUZxxl
quelle
Sieht so aus, als hätten wir die gleiche Lösung gefunden, aber Sie waren früher :(
orlp
@orlp Das passiert.
FUZxxl
3

19 Anweisungen

found:    PRINTX       # print input/found number
          DJZX done    # check if n == 1
          DJZX done    # after this point x == n - 2
parity:   INCY         # after this loop y == n // 2
          DJZX even
          DJZX odd
          JMP parity
odd-loop: DJZY found
          INCX
          INCX
odd:      INCX         # we enter mid-way to compute x = 6y + 4 = 3n + 1
          INCX
          INCX
          INCX
          JMP odd-loop
even:     DJZY found   # simply set x = y
          INCX
          JMP even
done:     HALT

Sie können es mit meinem Dolmetscher ausführen .

orlp
quelle
Duplikat meiner Antwort .
FUZxxl
@FUZxxl Das habe ich vor einer Stunde zu Ihnen gesagt: P
orlp
Ja, das hast du getan. Ich habe das geschrieben, damit andere die Gleichheit erkennen.
FUZxxl