Hallo. Mich würde Interessieren, wie der ATmega Divisionen von ganzen Zahlen ausführt. Und warum rundet der µc das Ergebnis von 15/16 (0,94) auf 0 und nicht auf 1?
Gaat11 schrieb: > Und warum rundet der µc das Ergebnis von 15/16 (0,94) auf 0 > und nicht auf 1? Das hat nichts mit dem ATmega zu tun, sondern mit der Programmiersprache C. Bei Division von zwei Integer-Zahlen und Speicherung in einer Integer-Variablen wird nur der Integer-Teil gespeichert. Und das ist die Zahl vor dem Komma. Schlag einfach mal Dein C-Buch auf ... Kapitel Datentypen.
:
Bearbeitet durch Moderator
Frank M. schrieb: > Das hat nichts mit dem ATmega zu tun, sondern mit der Programmiersprache > C. Bei Division von zwei Integer-Zahlen und Speicherung in einer > Integer-Variablen wird nur der Integer-Teil gespeichert. Und das ist die > Zahl vor dem Komma. > > Schlag einfach mal Dein C-Buch auf ... Kapitel Datentypen. Genau so war das. Danke für die schnelle Antwort.
Gaat11 schrieb: > Hallo. > > Mich würde Interessieren, wie der ATmega Divisionen von ganzen Zahlen > ausführt. Und warum rundet der µc das Ergebnis von 15/16 (0,94) auf 0 > und nicht auf 1? Ich nehme an, Du programmierst in C bzw. C++? Da verhält sich die Integer-Division genau so: als Division ohne Rest, egal auf welcher CPU.
Hallo, das macht der AVR nicht willkürlich, er hält sich damit an den C-Standard. Dabei werden ganzzahlige Divisionen nicht gerundet, sondern die Nachkommastellen abgeschnitten Gerundete Ergebnisse gehen so: Ergebnis = (Dividend + Divisor/2) / Divisor mfG N.G.
Weil es bei ganzen Zahlen keine Rundung gibt. Du kannst allerdings vor der Division den halben Divisor addieren.
https://www.mikrocontroller.net/articles/AVR-Tutorial:_Arithmetik8#Division Wenn Du integer gerundet rechnen willst, dann addiere vor der Division den halben Divisor auf: n n + d/2 --- -> gerundet: ---------- d d Die Division d/2 übersetzt der Compiler heutzutage nicht in eine aufwändige Division, sondern ersetzt sie durch einfaches Shift nach rechts. Viele Grüße, Stefan
Stefan K. schrieb: > Die Division d/2 übersetzt der Compiler heutzutage nicht in eine > aufwändige Division, sondern ersetzt sie durch einfaches Shift nach > rechts. Nö, nur bei unsigned darf er das machen. -1 / 2 = 0 -1 >> 1 = -1
Stefan K. schrieb: > https://www.mikrocontroller.net/articles/AVR-Tutor... > > Wenn Du integer gerundet rechnen willst, dann addiere vor der Division > den halben Divisor auf: > > n n + d/2 > --- -> gerundet: ---------- > d d > > Die Division d/2 übersetzt der Compiler heutzutage nicht in eine > aufwändige Division, sondern ersetzt sie durch einfaches Shift nach > rechts. > > Viele Grüße, Stefan Danke. Das werde ich mal versuchen. Ps: Ich benutze unsgiend
Peter D. schrieb: > Nö, nur bei unsigned darf er das machen. Ja, da gebe ich Dir recht. Aber auch in diesem Fall wird er keine Division daraus machen, sondern am Ende eine Shift-Operation:
1 | int n; // Y + 3, Y +4 |
2 | int e; // Y + 1, Y + 2 |
3 | |
4 | e = n / 2; |
5 | 854: 2b 81 ldd r18, Y+3 ; 0x03 |
6 | 856: 3c 81 ldd r19, Y+4 ; 0x04 |
7 | 858: 33 23 and r19, r19 |
8 | 85a: 14 f4 brge .+4 ; 0x860 <__stack+0x1> |
9 | 85c: 2f 5f subi r18, 0xFF ; 255 |
10 | 85e: 3f 4f sbci r19, 0xFF ; 255 |
11 | 860: 35 95 asr r19 |
12 | 862: 27 95 ror r18 |
13 | 864: 3a 83 std Y+2, r19 ; 0x02 |
14 | 866: 29 83 std Y+1, r18 ; 0x01 |
Das ist ein gutes Beispiel, warum man solche mathematischen Funktionen (heutzutage) den Compiler machen lässt. Gruß, Stefan
>das macht der AVR nicht willkürlich, er hält sich damit an den >C-Standard. Selten so einen BLÖDSINN gelesen. Der AVR hält sich nur an seine eigenen Regeln!
> Mich würde Interessieren, wie der ATmega Divisionen ... ausführt. Bezogen auf den 8bit Befehlssatz: Gar nicht. Er kann nur Integer Zahlen nur addieren, subtrahieren und schieben. Manche (aber nicht alle AVR') können außerdem Fließkommazahlen multiplizieren. Dividieren können sie nicht. Bezogen auf die Programmiersprache: Der Compiler zerlegt die Division in einfachere Teil-Operationen, die der Mikrocontroller kann. Im Prinzip so, wie man in der Schule auch das manuelle dividieren lernt. Am Besten ist, du schreibst das einfach mal in C oder C++ auf und lässt Dir vom Compiler ein Listing (*.lst Datei) erstellen. Dann siehst du den Assembler-Code, der dabei heraus kommt.
Stefan K. schrieb: > Peter D. schrieb: >> Nö, nur bei unsigned darf er das machen. > > Ja, da gebe ich Dir recht. Aber auch in diesem Fall wird er keine > Division daraus machen, sondern am Ende eine Shift-Operation: > >
1 | > int n; // Y + 3, Y +4 |
2 | > int e; // Y + 1, Y + 2 |
3 | >
|
4 | > e = n / 2; |
5 | > 854: 2b 81 ldd r18, Y+3 ; 0x03 |
6 | > 856: 3c 81 ldd r19, Y+4 ; 0x04 |
7 | > 858: 33 23 and r19, r19 |
8 | > 85a: 14 f4 brge .+4 ; 0x860 <__stack+0x1> |
9 | > 85c: 2f 5f subi r18, 0xFF ; 255 |
10 | > 85e: 3f 4f sbci r19, 0xFF ; 255 |
11 | > 860: 35 95 asr r19 |
12 | > 862: 27 95 ror r18 |
13 | > 864: 3a 83 std Y+2, r19 ; 0x02 |
14 | > 866: 29 83 std Y+1, r18 ; 0x01 |
15 | >
|
> Das ist ein gutes Beispiel, warum man solche mathematischen Funktionen > (heutzutage) den Compiler machen lässt. > > Gruß, Stefan Stimmt. Ein blöder ASM Programmierer würde wahrscheinlich sowas komisches wie lsr r19 ror r18 daraus machen. Viel zu wenig Zyklen! Und womit soll denn dann bitteschön der ganze Flash gefüllt werden?
Was macht denn der Compiler wenn man unsigned int nimmt? Eventuell ist ja dieser "Code" dem signed geschuldet, obwohl es selten ein signed braucht.
ASM Superprofi schrieb: > Stimmt. Ein blöder ASM Programmierer würde wahrscheinlich sowas > komisches wie > > lsr r19 > ror r18 > > daraus machen. Genau. Und dass -1/2 dann zu 32767 wird, daran stören sich nur haarspaltende Kleingeister.
ASM Superprofi schrieb: > Was macht denn der Compiler wenn man unsigned int nimmt?
1 | int div2 (int x) |
2 | {
|
3 | return x / 2; |
4 | }
|
5 | |
6 | unsigned udiv2 (unsigned x) |
7 | {
|
8 | return x / 2; |
9 | }
|
-->
1 | div2: |
2 | sbrc r25,7 |
3 | adiw r24,1 |
4 | .L3: |
5 | asr r25 |
6 | ror r24 |
7 | ret |
8 | |
9 | udiv2: |
10 | lsr r25 |
11 | ror r24 |
12 | ret |
>Manche (aber nicht alle AVR') können außerdem Fließkommazahlen >multiplizieren. Also falls du den MUL Befehl meinst, der multipliziert keine Fließkommazahlen;)
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.