# Zahlen Test --> gerade oder ungerade in Assembler



## Kirby.exe (18. Dez 2019)

Alsooo wir sollen ein Programm in Assembler schreiben, dass eine ganze Zahl einließt und überprüft ob diese Zahl gerade oder ungerade ist. Soweit so gut, jedoch bekomme ich bei meinem Code eine Endlosschleife und sehe ehrlich gesagt meinen Fehler nicht  Könnte mir jemand auf die Sprünge helfen? 

Hier ist eine Liste mit allen Befehlen:




Mein Code:


```
#Einlesen einer Zahl
addi zero t0 1
sysmove exc t0
syscall

#Zahl nach a0 kopieren
sysmove a0 I[0]

#Prüfen ob Zahl gerade ist
ldd t1 zero 0
ldd t2 zero 0
ldd t3 zero 1 #Register mit Inhalt 1
ldd t4 zero 0 #Register mit 0

#divide:
subi a0 t2 2 # Subtraktion  mit 2
ldd t2 a0 0 #Move nach a0
beq a0 t3 11 #Vergleich a0 mit 1
beq a0 t4 13 #Vergleiche a0 mit 0
jmp 6

#ungerade:
cout ungerade
syscall

#gerade:
cout gerade
syscall
```


----------



## mihe7 (18. Dez 2019)

Mir ist die Syntax noch nicht klar. Wie viele Bytes haben die Befehle? Sind die Zahlen 8 Bit breit? Wie funktioniert cout? Usw. Da fehlt die Häfte der Doku. Aber das Prinzip wäre IMO:

```
# Prüfen, ob Zahl gerade ist
xor t0 t0 t0   # t0 := 0
addi t0 t1 1   # t1 := t0+1 = 1
and a0 t1 t0  # t0 := a0 & 1
beq t0 t1 ungerade # if t0 == t1 (also 1), dann weiter mit ungerade, sonst mit gerade
#gerade:
cout gerade
syscall

#ungerade:
cout ungerade
syscall
```


----------



## Kirby.exe (18. Dez 2019)

mihe7 hat gesagt.:


> Mir ist die Syntax noch nicht klar. Wie viele Bytes haben die Befehle? Sind die Zahlen 8 Bit breit? Wie funktioniert cout? Usw. Da fehlt die Häfte der Doku.


Also die größe der Befehle ist mir ehrlich gesagt unbekannt  Ich kann dir mal die Documentation des Assemblers schicken 

Ich glaube jedoch dass xor t0 t0 t0   # t0 := 0 gegen die Konvention verstößt, da nur ein Befehl pro Zeile ausgeführt werden darf wegen lesen und schreiben ins selbe Register, dass wurde mir zumindest in der letzten Übungsserie angestrichen



mihe7 hat gesagt.:


> Wie funktioniert cout?


So wie ich das verstanden habe ist count einfach ein print Befehl 



mihe7 hat gesagt.:


> # Prüfen, ob Zahl gerade ist
> xor t0 t0 t0   # t0 := 0
> addi t0 t1 1   # t1 := t0+1 = 1
> and a0 t1 t0  # t0 := a0 & 1
> beq t0 t1 ungerade # if t0 == t1 (also 1), dann weiter mit ungerade, sonst mit gerade


Was macht xor genau? In der Dokumentation steht bitweises Exklusiv-Oder, jedoch kann ich mir nicht wirklich vorstellen was es genau tut. Warum addierst du auf t0? Habe ich vielleicht etwas falsch verstanden bei der division in assembler? Ich dachte man müsste subtrahieren.


----------



## mihe7 (18. Dez 2019)

Kirby_Sike hat gesagt.:


> Was macht xor genau? In der Dokumentation steht bitweises Exklusiv-Oder, jedoch kann ich mir nicht wirklich vorstellen was es genau tut.


XOR = Antivalenz = entweder oder  

Wertetabelle:

```
A | B | A XOR B
0 | 0 | 0
0 | 1 | 1
1 | 0 | 1
1 | 1 | 0
```

Bitweises XOR:

```
10101010
01010101 
-------- XOR
11111111
```
Dagegen

```
10101010
00001111
-------- XOR
10100101
```

Ein XOR zweier gleicher Zahlen liefert also 0. 


Kirby_Sike hat gesagt.:


> Warum addierst du auf t0?


Um eine 1 in t1 zu erhalten  In den Befehlen habe ich keinen gefunden, mit dem ich ein Register mit einem Immediate (Wert) setzen hätte können. Wo ein Immediate zugelassen ist: addi (darum auch das i am Ende).



Kirby_Sike hat gesagt.:


> Habe ich vielleicht etwas falsch verstanden bei der division in assembler? Ich dachte man müsste subtrahieren.


Könnte man, muss man aber nicht. Eine Binärzahl ist ungerade, wenn das 1er-Bit gesetzt ist


----------



## Kirby.exe (18. Dez 2019)

Ahhhh jetzt fühle ich mich um einiges schlauer xD

Ich bin trotzdem verwirrt ob der xor Befehl der Konvention entspricht xD:

Konvention:


> Pro Zeile darf höchstens 1 Befehl stehen.
> Befehlsname und die jeweiligen Argumente müssen mit mindestens einem Leerzeichen oder einem
> Tabulator getrennt sein. Vor dem Befehlsnamen darf kein Leerzeichen stehen.
> Bei den reinen Maschinenbefehlen wird nicht zwischen Majuskeln und Minuskeln, also Groß- und Kleinschreibung, unterschieden. Das gilt insbesondere für die Registernamen.
> ...


----------



## Meniskusschaden (18. Dez 2019)

Kirby_Sike hat gesagt.:


> Ich glaube jedoch dass xor t0 t0 t0 # t0 := 0 gegen die Konvention verstößt, da nur ein Befehl pro Zeile ausgeführt werden darf


Dir ist aber schon klar, dass `# t0 := 0` kein Bestandteil des Befehls ist, sondern nur ein erläuternder Kommentar von @mihe7 ?


----------



## Kirby.exe (18. Dez 2019)

Ja ich weiß und ich habe gerade etwas nachgedacht und gemerkt dass meine Frage kein Sinn macht xD

# ---> Kommentar Zeichen


----------



## mihe7 (18. Dez 2019)

Sehe zwar kein Problem mit der Konvention, aber dann halt per Addition... (ich wusste vor der Doku nicht, was es mit zero auf sich hat) Und: der Assembler kann Labels  

```
# Einlesen
addi zero t1 1
sysmove exc t1
syscall
sysmove a0 I[0]

# Prüfen, ob Zahl gerade ist
addi zero t0 0
and a0 t1 t0 
beq t0 t1 ungerade 

# gerade
cout gerade
jmp ende

# ungerade
ungerade:
cout ungerade

# ende
ende:
sysmove exc zero
syscall
```


----------



## Kirby.exe (18. Dez 2019)

Danke für deine Hilfe  Ich muss sagen das hat gerade mein Wissen bezogen auf den Uni Assembler um einiges geboostet xD Du bist einfach ein Master of Everything xD


----------



## mihe7 (18. Dez 2019)

Funktionierts wenigstens?


----------



## Kirby.exe (18. Dez 2019)

mihe7 hat gesagt.:


> Funktionierts wenigstens?


Jap musste den cout Befehl etwas um ändern, weil der Assembler es gerne mit sysmove in ein Ausgabe Register haben möchte ansonsten läuft alles


----------



## Kirby.exe (18. Dez 2019)

@mihe7 Ich hätte noch eine Frage, wenn ich jetzt zwei Zahlen einlesen möchte und prüfen will ob die zweite Zahl in den Natürlichen Zahlen liegt muss ich doch einfach prüfen ob 0 größer als das Speicher Register der Zahl ist ?

Also wie folgt:


```
# Einlesen Zahl 1
addi zero t1 1
sysmove exc t1
syscall
sysmove a0 I[0]

# Einlesen Zahl 2
einlesen:
addi zero t2 1
sysmove exc t2
syscall
sysmove a1 I[1]
bgt zero a1 einlesen
```


----------



## mihe7 (18. Dez 2019)

Kirby_Sike hat gesagt.:


> Natürlichen Zahlen liegt muss ich doch einfach prüfen ob 0 größer als das Speicher Register der Zahl ist ?


Deine Idee ist also, wenn 0 > x gilt, dann ist x keine natürliche Zahl. Das ist mathematisch richtig, wenn man die 0 als natürliche Zahl zählt, ob der Vergleich so funktioniert, ist eine andere Sache - und davon würde ich nicht ausgehen.

Für den Prozessor ist ein Register einfach Wort mit einer bestimmen Länge, hier 8 Bit. Was diese 8 Bit darstellen, weiß der Prozessor nicht (es könnte spezielle Prozessorbefehle geben, was hier aber nicht der Fall ist, wie ich meine). 

Werden zwei Register verglichen, passiert das über eine logische Schaltung. So lange die Bits der beiden Register - vom höchstwertigen Bit ausgehend - gleich sind, sind die Register gleich. An der ersten Position, an der das nicht mehr zutrifft, weiß man, welches Register größer ist:

```
r1  11100000
r2  11110000
    ^^^^
    ===<
```
Hier wäre also r1 < r2.

Die Frage ist jetzt, was die Register darstellen. Das können Zahlen ohne Vorzeichen sein, dann hat man je Register einen Wertebereich von 0 bis 255. In dem Fall stimmt der Vergleich: 00000001 < 11111111 (binär) entspricht 1 < 255 (dezimal).

Wenn es Zahlen mit Vorzeichen sind, dann ist die Frage, wie diese dargestellt werden. Üblicherweise wird das Zweierkomplement verwendet. Um eine Zahl zu negieren, werden die Bits invertiert und anschließend wird eine 1 addiert.

Wenn wir Beispielsweise die 1 negieren wollen, um -1 zu erhalten:

```
00000001    # 1 binär
11111110    # invertiert
11111111    # 1 addiert
```
-1 wird im Zweierkomplement also binär mit 11111111 dargestellt. 

Klar ist jetzt, dass der Vergleich nicht das gewünschte Ergebnis liefert, denn 00000001 < 11111111 (binär) würde jetzt dezimal 1 < -1 entsprechen.

Tatsächlich lässt sich viel einfacher feststellen, ob eine Zahl negativ ist, denn das 8. Bit ist das Vorzeichen. Daher lassen sich Zahlen von -128 bis +127 darstellen.

Wenn Du also eine Zahl im Zweierkomplement hast, brauchst Du nur zu testen, ob das 8. Bit gesetzt ist. Falls ja, hast Du eine negative Zahl.


----------



## Kirby.exe (19. Dez 2019)

Danke für deine Hilfe um die Uhrzeit  Nehmen wir mal an dass wir die Natürlichen Zahlen ohne die 0 haben wollen, dann müsste man doch einfach prüfen bei 8 bit Zahlen ob 1 (011111111 im ZK) > Register X ist und wenn true dann geht er weiter und wenn nicht kommt die Eingabeaufforderung erneut ?


----------



## mihe7 (19. Dez 2019)

Kirby_Sike hat gesagt.:


> ob 1 (011111111 im ZK)


1 ist im ZK auch 00000001. 01111111 wäre 127 - ganz normal. Nur die negativen Zahlen werden anders dargestellt.

Nachtrag: und ja, wenn 01111111 > registerX ist, dann liegt registerX im Bereich von 0 bis 127. Wenn Du die 0 nicht haben willst, musst Du nochmal explizit auf 0 prüfen.


----------



## Kirby.exe (19. Dez 2019)

mihe7 hat gesagt.:


> 1 ist im ZK auch 00000001. 01111111 wäre 127 - ganz normal. Nur die negativen Zahlen werden anders dargestellt.
> 
> Nachtrag: und ja, wenn 01111111 > registerX ist, dann liegt registerX im Bereich von 0 bis 127. Wenn Du die 0 nicht haben willst, musst Du nochmal explizit auf 0 prüfen.


Okee Dankeschön  ja gut ich glaube nach dem Pensum an Mathe heute in der Uni hatte mein Gehirn da scheinbar ein Timeout xD


mihe7 hat gesagt.:


> 1 ist im ZK auch 00000001


War das nicht die 1 im Einerkomplement oder verwirre ich mich gerade selber  ?


----------



## mihe7 (19. Dez 2019)

Kirby_Sike hat gesagt.:


> War das nicht die 1 im Einerkomplement oder verwirre ich mich gerade selber  ?


Letzteres: positive Zahlen werden immer gleich dargestellt. Unterschiede gibt es in der Darstellung negativer Zahlen. Ist das höchstwertige Bit eine 0, dann unterscheiden sich vorzeichenlose Ganzzahlen nicht von vorzeichenbehafteten Ganzzahlen.


----------



## Kirby.exe (19. Dez 2019)

ok dann hatte ich das scheinbar falsch in Erinnerung


----------



## Kirby.exe (20. Dez 2019)

@mihe7 könntest du mir eventuell nochmal für dumme erklären, wie ich es mir vorstellen kann wenn register verglichen werden. Also in dem Befehlsatz PHILO's...Ich hatte and sowas gedacht:

t3 ist einfach ein Register das die Zahl 0 enthält. Ich möchte prüfen ob die Ziffer größer als 0 ist und wenn nicht, dann neu einlesen.


```
einlesen:
addi zero t2 1
sysmove exc t2
syscall
sysmove a1 I[1]
bgt t3 a1 einlesen
```


----------



## mihe7 (20. Dez 2019)

Der Vergleich ist ganz einfach. Du hast zwei vorzeichenlose binäre Zahlen und die werden nicht anders verglichen dezimale Zahlen: 0 < 1 < 10 < 11 < 100 < 101 < 110 < 111 < 1000 usw.

Das einzige Problem ist, dass die Befehle keine negativen Zahlen kennen. Es gibt keine Zahl kleiner 0. Es obliegt dem Programmierer, wie er negative Zahlen darstellt. Der Programmierer des "Betriebssystems" in PHILO hat festgelegt, dass bei Eingabe (syscall) einer negativen Zahl das Zweierkomplement verwendet wird.

Ein Vergleich zweier negativen Zahlen ist somit  auch kein Problem: denn -2 < -1, was unmittelbar auch in ZK-Darstellung 11111110 < 11111111  zutrifft.

Problematisch ist der Vergleich einer negativen und einer nicht-negativen Zahl, der Befehl weiß ja nicht, ob eine Zahl negativ oder positiv ist. Was Du machen kannst: Du kannst fragen, ob eine Zahl größer als 127 (01111111) ist. Dann nämlich ist das 8. Bit, das Vorzeichenbit, gesetzt.


```
addi zero t3 127
einlesen: ...
...
bgt a1 t3 einlesen     # falls a1 > 127, also Vorzeichenbit gesetzt, dann weiter mit einlesen
```


----------



## Kirby.exe (20. Dez 2019)

Also ich habe mal meinen Code etwas überarbeitet etc. Es sollen halt eine ganze Zahl durch eine Natürliche Zahl(ohne 0) geteilt werden.

Das Problem ist es kommen sehr witzige Werte heraus die nicht wirklich etwas mit dem eigentlichen Wert zu tun haben

Mein Code dazu:


```
#Clear Register
addi zero t3 0
addi zero t6 1

#Erste Zahl einlesen
addi zero t1 1
sysmove exc t1
syscall
sysmove a0 I[0]
bgt t3 a0 multiplyT

#Zweite Zahl einlesen
einlesen:
addi zero t2 1
sysmove exc t2
syscall
sysmove a1 I[0]
bgt t3 a1 einlesen

laeuft:
addi a3 a3 1 #zähler wird erhöht

divide:
sub a0 a1 a0
bgt a0 a1 laeuft
beq t6 t4 mover

print:
sysmove O[0] a3
#cout Das Ergebnis lautet
addi zero t5 6
sysmove exc t5
syscall

end:
sysmove exc zero
syscall

multiplyT:
addi zero t4 1
sub t3 a0 a0
jmp einlesen

multiplyB:
addi zero t4 1
sub t3 a0 a0
jmp print

mover:
add zero a3 a0
jmp multiplyB
```


----------



## Kirby.exe (20. Dez 2019)

mihe7 hat gesagt.:


> Der Vergleich ist ganz einfach. Du hast zwei vorzeichenlose binäre Zahlen und die werden nicht anders verglichen dezimale Zahlen: 0 < 1 < 10 < 11 < 100 < 101 < 110 < 111 < 1000 usw.
> 
> Das einzige Problem ist, dass die Befehle keine negativen Zahlen kennen. Es gibt keine Zahl kleiner 0. Es obliegt dem Programmierer, wie er negative Zahlen darstellt. Der Programmierer des "Betriebssystems" in PHILO hat festgelegt, dass bei Eingabe (syscall) einer negativen Zahl das Zweierkomplement verwendet wird.
> 
> ...


Ich glaube das könnte der Grund für die komischen Werte sein xD


----------



## Kirby.exe (20. Dez 2019)

Könntest du dir mal meinen Code anschauen, ich glaube das steht einiges an Bullshit xD 

Ich habe gemerkt das mein Zähler register gar nicht 0 ist, jedoch kommt jetzt bei jeder Iteration der Wert 0 als Ergebnis 


```
#Clear Register
addi zero t3 0
addi zero t6 1
addi zero a3 0

#Erste Zahl einlesen
addi zero t1 1
sysmove exc t1
syscall
sysmove a0 I[0]
bgt t3 a0 negative

#Zweite Zahl einlesen
einlesen:
addi zero t1 1
sysmove exc t1
syscall
sysmove a1 I[0]
beq a1 t3 einlesen
bgt t3 a1 einlesen

divide:
sub a0 a1 a0
bgt a0 a1 laeuft
beq t6 t4 mover

print:
sysmove O[0] a3
#cout Das Ergebnis lautet
addi zero t5 6
sysmove exc t5
syscall

end:
sysmove exc zero
syscall

negative:
addi zero t4 1
sub t3 a0 a0
jmp einlesen

multiplyB:
sub t3 a0 a0
jmp print

mover:
add zero a3 a0
jmp multiplyB

laeuft:
addi a3 a3 1 #zähler wird erhöht
jmp divide
```


----------



## mihe7 (20. Dez 2019)

Kirby_Sike hat gesagt.:


> Es sollen halt eine ganze Zahl durch eine Natürliche Zahl(ohne 0) geteilt werden.


D. h. die Zahlen liegen beide im Eingabebereich von -128 bis +127?


----------



## Kirby.exe (20. Dez 2019)

Also ich glaube das mein Programm bereits funktioniert, jedoch ist der Counter(Ergebnis was gesprintet wird) immer um 1 zu niedrig  Ich sehe nur leider den Fehler nicht


----------



## Kirby.exe (20. Dez 2019)

mihe7 hat gesagt.:


> D. h. die Zahlen liegen beide im Eingabebereich von -128 bis +127?


Naja also die Natürliche Zahl (Nenner) ja die Ganzezahl(Zähler) darf alles sein von -unendlich bis +unendlich


----------



## mihe7 (20. Dez 2019)

Kirby_Sike hat gesagt.:


> Naja also die Natürliche Zahl (Nenner) ja die Ganzezahl(Zähler) darf alles sein von -unendlich bis +unendlich


Was bei 8 Bit etwas schwierig ist, oder? 

Mal eine andere Frage: funktioniert das `bgt t3 a0 negative`? Dann funktioniert der Vergleichsoperator anders als vermutet.


----------



## Kirby.exe (20. Dez 2019)

ja das tut er xD  er schaut ja ob t3(Wert = 0) größer als a0 ist und wenn ja springt er zu negative 
bgt = branch greater than


----------



## mihe7 (20. Dez 2019)

Gibts dieses PHILO-Teil eigentlich zum Download oder steht das nur den Studenten zur Verfügung?


----------



## Kirby.exe (20. Dez 2019)

Ich schicke es dir mal per PN  Brauchst du Unix oder Windows?

Ich kann dir keine PN schreiben lul, dann müsstest du mich eben anschreiben


----------



## mihe7 (20. Dez 2019)

Kirby_Sike hat gesagt.:


> ja das tut er xD er schaut ja ob t3(Wert = 0) größer als a0 ist und wenn ja springt er zu negative


Das scheint mir eine Wundermaschine zu sein, die automatisch weiß, ob 11111111 nun 255 oder -1 ist


----------



## mihe7 (20. Dez 2019)

Ach, jetzt sehe ich das erst, das Ding hat 32-Bit Register, verwenden intern vermutlich ein Java int und die Befehle arbeiten im Zweierkomplement... OK, dann ist alles klar.


----------



## Kirby.exe (20. Dez 2019)

mihe7 hat gesagt.:


> Das scheint mir eine Wundermaschine zu sein, die automatisch weiß, ob 11111111 nun 255 oder -1 ist


xD Ich kann es nicht mit Sicherheit sagen, aber es geht das Gerücht, sie bestehe aus Blut, Stahl und schwarzer Magie...


----------



## Kirby.exe (20. Dez 2019)

Ich glaube ich habe die Lösung  ich habe nicht den Fall im Label divide abgedeckt wenn a0 und a1 gleich sind xD Ich glaube es läuft  finally 

Danke für deine Hilfe


----------



## mihe7 (20. Dez 2019)

Kirby_Sike hat gesagt.:


> Danke für deine Hilfe


Welche Hilfe?!?


----------



## Kirby.exe (20. Dez 2019)

mentaler Beistand


----------



## mihe7 (20. Dez 2019)

LOL, ok  Aber einen habe ich noch, in multiplyB müsste es 


```
sub t3 a0 a3
```
heißen.


----------



## Kirby.exe (20. Dez 2019)

das hatte ich auch gemerkt und kam mir ziemlich blöd vor xD


----------

