Hallo Forum, mal wieder eine Verständnisfrage. Ich möchte zwei z.B 32
Bit zahlen von einander subtrahieren. Wenn ein Negatives Ergebnis
berechnet wird soll dies den gleichen Zahlenwert im positiven haben,
sprich aus -231983 soll 231983 werden. Bei eine 8-Bit-Subtraktion mache
ich das mit dem Befehel NEG wenn ein Übertrag ins Carry stattgefunden
hat. wie ist es bei einer 32-Bit-Zahl. Muß ich nach jeder
Teilsubtraktion überprüfen ob ein Übertrag stattgefunden hat und dann
den NEG-Befehl ausführen oder nur am Ende der vier Teilsubtraktionen bei
einem Carryübertrag dann viermal den NEG-Befehl. Oder soll ich den
COM-Befehl nehmen. ich weiß nicht warum, aber ich habe oft ein Ergebnis
welches sich um 1 zu einem mit Dezimal und den gleichen Zahlen
ausgeführten Rechnung unterscheidet.
Danke mal wieder für Eure Hilfe
Was bitte versuchst du da zu machen? Willst du den Absolutwert vom
Ergebnis der Subtraktion haben? und soll das Assembler auf einem 8 Bit
System sein? Rechnet das mit Einer- oder Zweierkomplement, je nachdem
halt COM oder auch nicht.
anfänger0815 schrieb:> aber ich habe oft ein Ergebnis> welches sich um 1
mit was für Code?
eventuell ein Problem mit der Zweierkomplement Darstellung?
> oder nur am Ende der vier Teilsubtraktionen
nur am Ende, denn nur dann ist die Zahl negativ geworden. Aber da würde
ich eher das Negativ Flag abfragen als das Carry flag, das kann nämlich
auch überlaufen wenn du von einer positiven Zahl eine negative abziehst.
Wäre halt interessant was für ein System du benutzt und was für Flags
das hat.
Große Entschuldigung. Ich arbeite im Moment mit einem Attiny84. Ich
verwende Assembler. Genau, ich möchte auf alle Fälle den Betrag einer
Subtraktion. Also keine Negativen Werte.
Mein Testcode sieht im Moment so aus:
ldi tmp10,40
ldi tmp12,30
sub tmp10,tmp12
ldi tmp11,20
ldi tmp12,30
sbc tmp11,tmp12
brcc hp10
neg tmp10
neg tmp11
hp10:
anfänger0815 schrieb:> Muß ich nach jeder> Teilsubtraktion überprüfen ob ein Übertrag stattgefunden hat und dann> den NEG-Befehl ausführen
Nein. NEG hilft dir nicht, wenn du es mit mehr als einem Byte zu tun
hast.
> oder nur am Ende der vier Teilsubtraktionen bei> einem Carryübertrag dann viermal den NEG-Befehl.
Nein. NEG hilft dir nicht, wenn du es mit mehr als einem Byte zu tun
hast.
> Oder soll ich den> COM-Befehl nehmen.
Das ist zielführender, reicht aber allein nicht.
> ich weiß nicht warum, aber ich habe oft ein Ergebnis> welches sich um 1 zu einem mit Dezimal und den gleichen Zahlen> ausgeführten Rechnung unterscheidet.
Nicht ganz. Wenn du COM verwendest, ist das Ergebnis immer um genau 1
daneben(zu klein). Das musst du also einfach nur kompensieren. Beispiel
für 16Bit:
sub R16,R18
sbc R17,R19
brpl positiv
com R16
com R17
subi R16,Low(-1)
sbci R17,High(-1)
positiv:
...
c-hater schrieb:> Beispiel für 16Bit:>> sub R16,R18> sbc R17,R19> brpl positiv
Es handelt sich wohl um die Subtraktion 2er unsigned Werte, zumindest
deutet darauf hin, dass der TO auf Carry vergleicht. Ergo:
1
BRSH positiv
2
;; oder
3
BRCC positiv
> com R16> com R17> subi R16,Low(-1)> sbci R17,High(-1)
Geht kürzer:
1
neg R17
2
neg R16
3
sbci R17, 0 ; oder sbc R17, Rzero wenn Rzero = 0.
Und wieder hat der c-hater was vom C-Compiler gelernt :-P
Negation für 32 Bits:
Johann L. schrieb:> Geht kürzer:>> neg R17> neg R16> sbci R17, 0 ; oder sbc R17, Rzero wenn Rzero = 0.>> Und wieder hat der c-hater was vom C-Compiler gelernt :-P
Das ging mir auch schon oft so.
Wenn ich erfahren wollte, ob es für eine bestimmte Rechenoperation einen
coolen Assemblertrick gibt, fragte ich einfach den Compiler um Rat und
war von seinen Antworten meist positiv überrascht.
Irgendwann hat es mir aber gereicht, und ich habe den Compiler
angebrüllt: "Wenn du sowieso immer alles besser weißt, dann erledige
doch dieses Assemblergefrickel selber, und zwar bitte komplett!"
Er war sofort damit einverstanden, und seitdem gebe ich – in einer für
uns beide gut verständlichen Sprache – nur noch grob vor, was ich gerne
hätte, und der Compiler übernimmt für mich dann netterweise die lästige
Assemblerprogrammierung.
Und das mit einem Tempo, dass einem die Spucke wegbleibt: Zehntausende
Assemblerzeilen in Sekundenschnelle und dabei auch noch fehlerfrei, das
muss ihm erst einmal einer nachmachen.
Und er meckert nicht einmal, wenn ich von ihm verlange, fast dasselbe
Assemblerprogramm mit nur ein paar kleinen Änderungen noch einmal
komplett neu zu schreiben.
anfänger0815 schrieb:> Muß ich nach jeder> Teilsubtraktion überprüfen ob ein Übertrag stattgefunden hat und dann> den NEG-Befehl ausführen oder nur am Ende der vier Teilsubtraktionen bei> einem Carryübertrag dann viermal den NEG-Befehl
Nee, du mußt mal deinen Rechner "oben" einschalten...wenn du Zahlen
subtrahierst (oder addierst) dann machst du das immer mit "Carry"
(natürlich nicht bei der niedrigsten Stelle...) und dann kannst du das
Ergebnis "verabsolutieren"...was immer dein Assembler dafür an Befehlen
bereit stellt. Schau dir mal die vielen Assembler-Beispiele für
fundamentale Rechenoperationen an, die es im Netz gibt. Oder schau dir
halt an, was dein Compiler aus "abs(sign-32 minus sign-32)" macht.
Gruß Rainer
Yalu X. schrieb:> Und das mit einem Tempo, dass einem die Spucke wegbleibt: Zehntausende> Assemblerzeilen in Sekundenschnelle und dabei auch noch fehlerfrei, das> muss ihm erst einmal einer nachmachen.
Und wenn mal wieder die Calling-Conventions nicht stimmen, und deshalb
das Programm abstürzt ist der Compiler völlig hilflos und fragt dann
doch ob sich mal bitte jemand den Assemblercode anschauen kann ;-)
Guest schrieb:> Und wenn mal wieder die Calling-Conventions nicht stimmen,
Das ist mir bisher eigentlich nur passiert, wenn ich selber
Assemblercode in den Compiler-Output gefrickelt habe. Eigentlich alle
Compiler, mit denen ich bisher zu tun hatte, konnten mit ihren eigenen
Calling-Conventions zuverlässig umgehen.
Yalu X. schrieb:> "Wenn du sowieso immer alles besser weißt, dann erledige> doch dieses Assemblergefrickel selber, und zwar bitte komplett!"
Zu genau dieser Meinung kam ich auch vor 15 Jahren (gcc 3.x / x86). Ich
schaffte es nicht mehr, schnelleren Code "per Hand" zu erzeugen. Das mag
bei µC noch funktionieren, auf x86 kaum.
leo
Guest schrieb:> Yalu X. schrieb:>> Und das mit einem Tempo, dass einem die Spucke wegbleibt: Zehntausende>> Assemblerzeilen in Sekundenschnelle und dabei auch noch fehlerfrei, das>> muss ihm erst einmal einer nachmachen.>> Und wenn mal wieder die Calling-Conventions nicht stimmen, und deshalb> das Programm abstürzt ist der Compiler völlig hilflos und fragt dann> doch ob sich mal bitte jemand den Assemblercode anschauen kann ;-)
Wenn man keine Lust hat Assembler selber zu schreiben, muß das ja nicht
bedeuten, daß man Assembler nicht mehr lesen kann.
leo schrieb:> Das mag bei µC noch funktionieren, auf x86 kaum.
Vor allem dann nicht, wenn sich bestimmte Implementationen in ihrem
Verhalten deutlich voneinander unterscheiden. Befehlssequenzen, die auf
einem x86 absolut optimal sind, sind auf einem anderen x86 überraschend
langsam (z.B. "REP RET").
leo schrieb:> Yalu X. schrieb:>> "Wenn du sowieso immer alles besser weißt, dann erledige>> doch dieses Assemblergefrickel selber, und zwar bitte komplett!">> Zu genau dieser Meinung kam ich auch vor 15 Jahren (gcc 3.x / x86). Ich> schaffte es nicht mehr, schnelleren Code "per Hand" zu erzeugen. Das mag> bei µC noch funktionieren, auf x86 kaum.>> leo
Vor allem kann man sich mit einem Compiler auf einem ganz anderen Niveau
unterhalten.