Forum: Mikrocontroller und Digitale Elektronik Division ATmega


von Gaat11 (Gast)


Lesenswert?

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?

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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
von Gaat11 (Gast)


Lesenswert?

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.

von Georg B. (diereinegier)


Lesenswert?

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.

von N. G. (newgeneration) Benutzerseite


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

Weil es bei ganzen Zahlen keine Rundung gibt.
Du kannst allerdings vor der Division den halben Divisor addieren.

von Stefan K. (stefan64)


Lesenswert?

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

von Peter D. (peda)


Lesenswert?

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

von Gaat11 (Gast)


Lesenswert?

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

von Stefan K. (stefan64)


Lesenswert?

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

von ASM Superprofi (Gast)


Lesenswert?

>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!

von Stefan F. (Gast)


Lesenswert?

> 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.

von ASM Superprofi (Gast)


Lesenswert?

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?

von ASM Superprofi (Gast)


Lesenswert?

Was macht denn der Compiler wenn man unsigned int nimmt? Eventuell ist 
ja dieser "Code" dem signed geschuldet, obwohl es selten ein signed 
braucht.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

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.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

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

von ASM Superprofi (Gast)


Lesenswert?

Gut, ich nehme meine Stichelei hiermit zurück ;)

von holger (Gast)


Lesenswert?

>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
Noch kein Account? Hier anmelden.