Für die minimalistische Programmiersprache JASm, die mit nur zwei Befehlen auskommt, wurden schon eine Reihe an Algorithmen vorgestellt. Unter anderem auch zur Addition und Multiplikation von Zahlen.
In diesem Beitrag werden die vorgestellten Codebeispiele länger, obwohl die eigentlich damit realisierten Funktionen nach wie vor eher “einfacher” Natur sind. So gehört die Division eigentlich zum Kernelement einer Programmiersprache, bei JASm, welches nur die Subtraktion (und einen Sprung) kennt, liegt dies anders.
Neben der Division werden auch ein paar logische Operationen vorgestellt.
Null? Und? Oder?
Wie bereits dargestellt, besitzt JASm einen Operator für einen bedingten Sprung: JA. Dieser versetzt den Programmzeiger auf eine andere Adresse, wenn der zu überprüfende Wert größer als Null ist. Im anderen Fall, wird mit der nächsten Codezeile fortgefahren.
Um zu prüfen, ob ein Wert exakt gleich Null ist, ist es also erforderlich die beiden anderen Kriterien (größer als Null und kleiner als Null) auszuschließen. Im konventionellen Pseudo-Code sieht dies wie folgt aus:
if (a > 0) goto ungleichNull if (a < 0) goto ungleichNull /* a ist gleich null */ ...
Oder im JASm Code:
a: 0 # zu überprüfender Wert tmp: 0 # Pufferspeicher JA @a @ungleichNull SUB @tmp @a # a negieren (tmp = -a) JA @tmp @ungleichNull gleichNull: ... # Code für den Fall, dass a = 0 ungleichNull: ... # Code für den Fall, dass a!= 0
Diese Implementierung entspricht auch zugleich einer Oder-Bedingung:
if (a>0 || a<0) goto ungleichNull
Bekanntlich lässt sich diese Logik auch negieren zu einer äquivalenten Und-Bedingung
if (!a>0 && !a<0) goto ungleichNull
Größter gemeinsamer Teiler (ggT), der Euklidische Algorithmus
Bei der Berechnung des größten gemeinsamen Teilers (ggT) von zwei Zahlen, handelt es sich um wohl einen der ältesten Algorithmen. Zum Einsatz kommt der Euklidische Algorithmus in seiner Reinform, also ohne Modulus Berechnung.
Die folgende Implementierung implementiert den Algorithmus als Makro.
EUCLID: REM b = abs(b) SUB @EUCLID_tmp @EUCLID_tmp # init tmp JA @EUCLID_b @EUCLID_bispos SUB @EUCLID_neg @EUCLID_neg # init neg SUB @EUCLID_neg @EUCLID_b # neg = -b SUB @EUCLID_tmp @EUCLID_neg # tmp = b SUB @EUCLID_b @EUCLID_b # b = 0 SUB @EUCLID_b @EUCLID_tmp # b = -b EUCLID_bispos: REM if a!=0 => goto loop JA @EUCLID_a @EUCLID_loop # a>0 goto loop SUB @EUCLID_neg @EUCLID_neg # init neg SUB @EUCLID_neg @EUCLID_a # neg = -a SUB @EUCLID_tmp @EUCLID_neg # tmp = a SUB @EUCLID_a @EUCLID_a # a = 0 SUB @EUCLID_a @EUCLID_tmp # a = -a JA @EUCLID_a @EUCLID_loop # "a"<0 goto loop REM a==0 => return b SUB @EUCLID_tmp @EUCLID_tmp # init tmp SUB @EUCLID_tmp @EUCLID_b # tmp = -b EUCLID_finish: # return tmp SUB @EUCLID_result @EUCLID_result # init result SUB @EUCLID_result @EUCLID_tmp # result = -tmp SUB @EUCLID_a @EUCLID_a # init a for later use SUB @EUCLID_b @EUCLID_b # init b for later use EUCLID_return: JA 0 0 # return to caller EUCLID_loop: REM if b!=0 goto innerloop JA @EUCLID_b @EUCLID_innerloop # b>0 goto innerloop SUB @EUCLID_tmp @EUCLID_tmp # init tmp SUB @EUCLID_tmp @EUCLID_b # tmp = -b JA @EUCLID_tmp @EUCLID_innerloop # b<0 goto innerloop REM b==0 return a SUB @EUCLID_tmp @EUCLID_tmp # init tmp SUB @EUCLID_tmp @EUCLID_a # tmp = -a JA 0 @EUCLID_finish # goto finish EUCLID_innerloop: # if a>b then a-=b else b-=a SUB @EUCLID_tmp @EUCLID_tmp # init tmp SUB @EUCLID_tmp @EUCLID_b # tmp = -b SUB @EUCLID_neg @EUCLID_neg # init neg SUB @EUCLID_neg @EUCLID_a # neg = -a SUB @EUCLID_tmp @EUCLID_neg # tmp = -b + a JA @EUCLID_tmp @EUCLID_agreaterb # a>b goto agreaterb SUB @EUCLID_b @EUCLID_a # b -= a JA 0 @EUCLID_loop EUCLID_agreaterb: # a>b SUB @EUCLID_a @EUCLID_b # a -= b JA 0 @EUCLID_loop EUCLID_a: 0 # input variable a EUCLID_b: 0 # input variable b EUCLID_tmp: 0 # internal buffer EUCLID_neg: 0 # internal buffer for -a oder -b