Forum: Mikrocontroller und Digitale Elektronik Division mit "krummen" 10


von Draco (Gast)


Lesenswert?

Für eine Umwandlung von DEC Zahlen in das ASCII Format muss ich nach für 
die Anzahl der Stellen immer durch 10 teilen. Ich arbeite mit einem 
Atmega32u4, dieser hat ja nun auch keine Hardwaredivision. Gibt es eine 
bessere Alternative als ein x/10? Vielleicht ein bitshift mit 
aufaddieren?

von Joachim B. (jar)


Lesenswert?

Draco schrieb:
> Für eine Umwandlung von DEC Zahlen in das ASCII Format muss ich nach für
> die Anzahl der Stellen immer durch 10 teilen

wieso das denn?

itoa ltoa ultoa dtostr wäre eine Möglichkeit, sprintf eine andere

von Route_66 H. (route_66)


Lesenswert?

Hallo!
Wieviel Dezimalstellen hat deine Zahl?

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Draco schrieb:
> Gibt es eine
> bessere Alternative als ein x/10? Vielleicht ein bitshift mit
> aufaddieren?

Zumindest hier:

http://stackoverflow.com/questions/5558492/divide-by-10-using-bit-shifts

findet man eine Shift-Add-Variante. Aber ob die tatsächlich schneller 
ist?

von Peter D. (peda)


Lesenswert?

Draco schrieb:
> dieser hat ja nun auch keine Hardwaredivision.

Na und?
Wieviel Millionen ASCII-Zeichen mußt Du denn je Sekunde ausgeben?

von Stefan F. (Gast)


Lesenswert?

Überlass das mal dem Compiler, der wird schon guten Code erzeugen.

Für a=b/2 und a=b<<1 erzeugt der Compiler exakt den selben Bytecode.

von Rene K. (xdraconix)


Lesenswert?

Joachim B. schrieb:
> wieso das denn?
>
> itoa ltoa ultoa dtostr wäre eine Möglichkeit, sprintf eine andere

Frank M. schrieb:
> findet man eine Shift-Add-Variante. Aber ob die tatsächlich schneller
> ist?

Peter D. schrieb:
> Na und?
> Wieviel Millionen ASCII-Zeichen mußt Du denn je Sekunde ausgeben?

Es geht nicht um Geschwindigkeitsvorteile, es geht um Platzersparnis.

Frank M. schrieb:
> Zumindest hier:
>
> http://stackoverflow.com/questions/5558492/divide-by-10-using-bit-shifts

Vielen Dank, das sieht vielversprechend aus, das schaue ich mir mal an!

von Peter D. (peda)


Lesenswert?

Rene K. schrieb:
> Es geht nicht um Geschwindigkeitsvorteile, es geht um Platzersparnis.

Beitrag "Re: 8bis32bit binär in Dezimal ausgeben"

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Draco schrieb:
> Für eine Umwandlung von DEC Zahlen in das ASCII Format muss ich nach für
> die Anzahl der Stellen immer durch 10 teilen. Ich arbeite mit einem
> Atmega32u4, dieser hat ja nun auch keine Hardwaredivision. Gibt es eine
> bessere Alternative als ein x/10?
Ich würde vermuten, der Compiler kann die Division durch die Konstante 
so gut optimieren, dass jede andere Lösung umständlicher wäre.

> Vielleicht ein bitshift mit aufaddieren?
Das geht nur dann efizient, wenn du beliebigen Zugriff auf die einzelnen 
Bits hast. Also: nimm ein FPGA.
http://www.lothar-miller.de/s9y/categories/44-BCD-Umwandlung

Frank M. schrieb:
> findet man eine Shift-Add-Variante. Aber ob die tatsächlich schneller ist?
Sicher nicht auf einem Rechenknecht, der nur 8 Bit kann und dann schon 
wieder mit einem Übertrag rumhampeln muss und keinen Nibble-Zugriff 
beherrscht...

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Stefan U. schrieb:
> Für a=b/2 und a=b<<1 erzeugt der Compiler exakt den selben Bytecode.

Bestimmt nicht. Ersteres ist eine Division, letzteres eine 
Plutimikation ;-)

von Pandur S. (jetztnicht)


Lesenswert?

Allenfalls zu beginn weg in BCD rechnen ?

von Stefan F. (Gast)


Lesenswert?

>> Für a=b/2 und a=b<<1 erzeugt der Compiler exakt den selben Bytecode.
> Bestimmt nicht.

Sorry, die Pfeile sind natürlich falsch herum.

von m.n. (Gast)


Lesenswert?

Draco schrieb:
> bessere Alternative als ein x/10?

x * 0,1

von Stefan F. (Gast)


Lesenswert?

> Allenfalls zu beginn weg in BCD rechnen ?

AVR's haben doch gar keine BCD Operationen.

von Pandur S. (jetztnicht)


Lesenswert?

>> Allenfalls zu beginn weg in BCD rechnen ?
>
>AVR's haben doch gar keine BCD Operationen.

So schwierig ist das nun auch wieder nicht.

von Stefan F. (Gast)


Lesenswert?

>>> Allenfalls zu beginn weg in BCD rechnen ?
>> AVR's haben doch gar keine BCD Operationen.
> So schwierig ist das nun auch wieder nicht.

Aber es macht doch keinen Sinn, Daten im BCD Format zu speichern, wenn 
es keine dazu passenden Operationen gibt. Dann müsste man doch vor und 
nach jeder Operation konvertieren. Damit gewinnt der TO nichts.

von Stefan F. (Gast)


Lesenswert?

>> bessere Alternative als ein x/10?
> x * 0,1

Ach komm schon, jetzt wird's aber schäbig.

von Rene K. (xdraconix)


Lesenswert?

Sooo.. ganz dämlich und einfach - einfach ne Multiplikation mit 0.1:
1
uint16_t mul01(uint16_t divisior)
2
{
3
  return divisior * 0.1;
4
}
5
6
void own_utoa( uint16_t uIntValue, char* Buffer )
7
{
8
  uint8_t i = 0;
9
  char temp;
10
11
  while( uIntValue > 0 )
12
  {
13
    Buffer[i++] = '0' + (uIntValue % 10);
14
    uIntValue = mul01(uIntValue);     // Hierfür!!!
15
  }
16
17
18
    for( uint8_t j = 0; j < i / 2; ++j )
19
    {
20
      temp = Buffer[j];
21
      Buffer[j] = Buffer[i-j-1];
22
      Buffer[i-j-1] = temp;
23
    }
24
    Buffer[i] = '\0';
25
}

Das hat den Sourcecode um satte 500 Bytes minimiert bei nur einer 16Bit 
Ausgabe (Dec: 786).

Mit mul01(uIntValue) :
1
Program Memory Usage   :  4508 bytes   13,8 % Full
2
Data Memory Usage   :  70 bytes   2,7 % Full


Mit uIntValue /= 10 :
1
Program Memory Usage   :  5072 bytes   15,5 % Full
2
Data Memory Usage   :  70 bytes   2,7 % Full

Eine Multiplikation mit Ganzzahlen und Bitshift hat nicht so den 
erhofften Erfolg gebracht ((divisior * 205) >> 11;) - der dort mit 32bit 
gerechnet werden muss um kein Overflow herbeizuführen, bringt nicht 
sonderliche Vorteile und ist auf 1024 begrenzt:
1
Program Memory Usage   :  4506 bytes   13,8 % Full
2
Data Memory Usage   :  70 bytes   2,7 % Full

von Joachim B. (jar)


Lesenswert?

Stefan U. schrieb:
>>> bessere Alternative als ein x/10?
>> x * 0,1
>
> Ach komm schon, jetzt wird's aber schäbig.

OK ganzzahlig *10/100 (scnr)

Rene K. schrieb:
> Es geht nicht um Geschwindigkeitsvorteile, es geht um Platzersparnis.

nächst größeren nehmen, wozu um Cent zu sparen zu lange am Code sitzen?

von Rene K. (xdraconix)


Lesenswert?

Joachim B. schrieb:
> nächst größeren nehmen, wozu um Cent zu sparen zu lange am Code sitzen?

In der u4 Reihe ist der Mega32 der größte IMHO.

von Joachim B. (jar)


Lesenswert?

isn Argument, bis jetzt habe ich lieber nach m328p den m1284p genommen, 
den m32u4 muss ich erst noch kennenlernen, liegt schon hier rum.

von Rene K. (xdraconix)


Lesenswert?

Joachim B. schrieb:
> isn Argument, bis jetzt habe ich lieber nach m328p den m1284p genommen,
> den m32u4 muss ich erst noch kennenlernen, liegt schon hier rum.

Ist nen feines Teil mit dem "On-Board" USB - wenn man da was größeres 
will muss man in der AT90USB Reihe rumstöbern. Das ist dann aber leider 
nimmer Pinkompatibel.

von Peter D. (peda)


Lesenswert?

Rene K. schrieb:
> Es geht nicht um Geschwindigkeitsvorteile, es geht um Platzersparnis.

Ich habs grad mal compiliert, itoa() benötigt wahnsinnig enorme, extrem 
riesige, unvorstellbar gigantische 134 Byte Flash, das sind volle 0,4% 
Deines ATmega32.
Findest Du es nicht selber lachhaft, darum so ein Getöse zu machen?

von Rene K. (xdraconix)


Lesenswert?

Peter D. schrieb:
> Ich habs grad mal compiliert, itoa() benötigt wahnsinnig enorme, extrem
> riesige, unvorstellbar gigantische 134 Byte Flash, das sind volle 0,4%
> Deines ATmega32.
> Findest Du es nicht selber lachhaft, darum so ein Getöse zu machen?

Das Argument lasse ich gelten :-D Leider muss ich viele Werte umwandeln 
um sie via UART rauszuschicken. In der Summierung macht sich das schon 
bezahlbar ja. Und "Getöse" war es ja nichtmal, ging ja alles flott von 
der Hand und hat mich ja auch zeitlich nicht sonderlich aufgehalten.

Das andere wäre ja auch noch eine Spur einfacher gewesen, ich könnte ja 
auch die Daten direkt rausschicken und auf dem Host die Umrechnung 
machen lassen. Aber so isses schöner, passt, is kleiner und läuft.

von S. R. (svenska)


Lesenswert?

Rene K. schrieb:
> Leider muss ich viele Werte umwandeln um sie via UART rauszuschicken.
> In der Summierung macht sich das schon bezahlbar ja.

Dir ist aber schon klar, dass itoa() eine Funktion ist, die nur einmal 
im Flash gespeichert werden muss, oder?

von Peter D. (peda)


Lesenswert?

Rene K. schrieb:
> In der Summierung macht sich das schon
> bezahlbar ja.

Nein, eben nicht. Die Routine wird nur einmal angelegt, egal wie oft Du 
sie aufrufst.
Um die Aufrufkosten zu senken, hilft z.B. eine Schleife, statt 
haufenweise Copy&Paste.

von Bernd K. (prof7bit)


Lesenswert?

Stefan U. schrieb:
> Überlass das mal dem Compiler, der wird schon guten Code erzeugen.
>
> Für a=b/2 und a=b<<1 erzeugt der Compiler exakt den selben Bytecode.

Erstens hast Du da was verdreht (du meintest Rechtsschift) und zweitens 
hab ich schon Compiler gesehen (vorzugsweise solche die mit K anfangen 
und mit l aufhören und viel Geld verlangen) die sind nicht imstande eine 
Division durch eine 2^n Konstante als solche zu erkennen und ziehen dann 
die komplette Integer-Division mit rein.

Allerdings muss man sich beim Rechtsschift vorher schlau machen was auf 
dieser Platform und bei diesem Compiler mit negativen Zahlen passiert.

von Stefan F. (Gast)


Lesenswert?

> Allerdings muss man sich ... schlau machen was auf ...mit negativen
> Zahlen passiert.

Es geht um unsigned Integer, die können nicht negativ werden.
Aber der Hinweis ist sinnvoll, bei signed Integer muss man aufpassen.

> hab ich schon Compiler gesehen ... die sind nicht imstande (sind) eine
> Division durch eine 2^n Konstante als solche zu erkennen und ziehen
> dann die komplette Integer-Division mit rein.

Na das sind ja erstaunlich dumme Compiler. Nicht mehr sonderlich 
Zeitgemäß, würde ich mal sagen.

von Jobst Q. (joquis)


Lesenswert?

Manche Compiler machen das schon ganz pfiffig:

https://blog.fefe.de/?ts=a922623d

von Christoph db1uq K. (christoph_kessler)


Lesenswert?

https://www.mikrocontroller.net/articles/AVR_Arithmetik#Bin.C3.A4r_zu_BCD_-_Umwandlung
Die Addition von 0x33 ist trickreich

Die Formulierung am Anfang sollte sicher "HEX zu ASCII" heissen, nicht 
"DEC zu ASCII". Das wäre ja zu einfach.

von m.n. (Gast)


Lesenswert?

Stefan U. schrieb:
>>> bessere Alternative als ein x/10?
>> x * 0,1
>
> Ach komm schon, jetzt wird's aber schäbig.

Das "schäbig" mußt Du mir schon begründen.

Wenn es nur Integer-Zahlen sein sollen geht es auch mit Subtraktionen: 
Beitrag "Re: ADC-Wert auf 4 7-Segmentanzeigen darstellen ohne viel Rechenleistung"
Wieviel Byte da nun gebraucht werden, habe ich nicht gezählt.

von W.A. (Gast)


Lesenswert?

m.n. schrieb:
> Draco schrieb:
>> bessere Alternative als ein x/10?
>
> x * 0,1

Das mach mal vor. Den Unterschied zwischen 1/10 und 1.0/10.0 kennst du?

von m.n. (Gast)


Lesenswert?

W.A. schrieb:
> Das mach mal vor. Den Unterschied zwischen 1/10 und 1.0/10.0 kennst du?

Für x = 123.456

x / 10  = 12.3456
x * 0.1 = 12.3456

Bitteschön ;-)

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Was war nochmal das Argument gegen Funktionen der AVR-LibC wie itoa, 
utoa, ltoa und ultoa?

von Double Dabble (Gast)


Lesenswert?

Double Dabble ist recht einfach.

von Jobst M. (jobstens-de)


Lesenswert?

Double Dabble schrieb:
> Double Dabble ist recht einfach.

Und es ist genau das:

Draco schrieb:
> Vielleicht ein bitshift mit aufaddieren?

https://en.wikipedia.org/wiki/Double_dabble


Gruß

Jobst

von Stefan F. (Gast)


Lesenswert?

>>>> bessere Alternative als ein x/10?
>>> x * 0,1
>> Ach komm schon, jetzt wird's aber schäbig.
> Das "schäbig" mußt Du mir schon begründen.

x*0,1 ist genau das Gleiche wie x/10. Nicht nur Mathematisch, sondern 
auch für den Mikrocontroller. Der Compiler erzeugt in beiden Fällen des 
selben Code.

Der Vorschlag ist daher vollkommen sinnlos.

von Timm T. (Gast)


Lesenswert?

Stefan U. schrieb:
> Der Compiler erzeugt in beiden Fällen des
> selben Code.

Der Compiler verwendet dafür aber aufgrund fehlenden Wissens eine 
Softdivisionsfunktion mit entsprechend langer Laufzeit. Genau das will 
der TO ja nicht.

Hier mal ein Beispiel für einen vorzeichenbehafteten 16-bit-Wert in 
ASCII, führende Nullen werden weggelassen, ein Dezimalpunkt wird 
eingefügt. Es ist also ein Festkommawert mit einer Nachkommastelle, 
deswegen nicht bei den Stellen verwirren lassen.
1
/**** Ausgabe als -####.# oder ####.# an RS232 ****/
2
3
void  write_snnnndn(int16_t value) {
4
  uint8_t tchr, lz;
5
  
6
  lz = 1;
7
  if (value < 0) {    // wenn negativ, invertieren und Minus
8
    value = -value;
9
    tchr = '-';
10
    serial_write(tchr);
11
  }
12
  tchr = '0';
13
  while (value >= 10000) {    // Tausender
14
    value -= 10000;
15
    tchr++;
16
  }
17
  if (!(tchr=='0')) {
18
    serial_write(tchr);
19
    lz = 0;
20
  }
21
  tchr = '0';
22
  while (value >= 1000) {    // Hunderter
23
  value -= 1000;
24
  tchr++;
25
  }
26
  if (!(tchr=='0') || !lz) {
27
    serial_write(tchr);
28
    lz = 0;
29
  }
30
  tchr = '0';
31
  while (value >= 100) {    // Zehner
32
    value -= 100;
33
    tchr++;
34
  }
35
  if (!(tchr=='0') || !lz) {
36
    serial_write(tchr);
37
  }
38
  tchr = '0';
39
  while (value >= 10) {    // Einer
40
    value -= 10;
41
    tchr++;
42
  }
43
  serial_write(tchr);
44
  serial_write('.');
45
  tchr = '0';
46
  while (value >= 1) {    // Nachkomma
47
    value -= 1;
48
    tchr++;
49
  }
50
  serial_write(tchr);
51
}

In ASM geht das noch etwas knapper, aber das würde die Koniferen hier im 
Forum verwirren.

von Double Dabble (Gast)


Lesenswert?

> Und es ist genau das:

> Draco schrieb:
>> Vielleicht ein bitshift mit aufaddieren?

Dann soll er das gefälligst auch hinschreiben.

von Jobst M. (jobstens-de)


Lesenswert?

Double Dabble schrieb:
> Dann soll er das gefälligst auch hinschreiben.

??

Steht im Eröffnungspost.


Gruß

JObst

von m.n. (Gast)


Lesenswert?

Stefan U. schrieb:
> x*0,1 ist genau das Gleiche wie x/10. Nicht nur Mathematisch, sondern
> auch für den Mikrocontroller. Der Compiler erzeugt in beiden Fällen des
> selben Code.

Eben nicht! Selbst bei einem AVR8 besteht ein Unterschied zwischen 
Multiplikation, die mit dem MUL-Befehl verkürzt und beschleunigt werden 
kann, und der Division, die deutlich aufwendiger mit Subtraktionen und 
Bitschieberei erledigt werden muß.

Bei der Fragestellung x/10 gehe ich bei x zunächst einmal von einer 
reellen Zahl aus, weshalb ein Vorschlag von itoa() für x ein Integer 
impliziert. Das geht aber aus der Eingangsfrage nicht eindeutig hervor.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

m.n. schrieb:
> Bei der Fragestellung x/10 gehe ich bei x zunächst einmal von einer
> reellen Zahl aus
Ich gehe in Verbindung mit uC immer zuallererst von dessen generischem 
Format, also einer Ganzzahl in binärer Darstellung (aka Integer) aus.

Demnach berechnet der die Division mit Erebnis und Rest, und eben nicht 
mit einer rellen Zahl als Resultat.

: Bearbeitet durch Moderator
von m.n. (Gast)


Lesenswert?

Lothar M. schrieb:
> m.n. schrieb:
>> Bei der Fragestellung x/10 gehe ich bei x zunächst einmal von einer
>> reellen Zahl aus
> Ich gehe in Verbindung mit uC immer zuallererst von dessen generischem
> Format, also einer Ganzzahl in binärer Darstellung (aka Integer) aus.

Ja gut, dann bezeichne ich diesen Typen aber mit i, j, k, ... und nicht 
mit x, y, z.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

m.n. schrieb:
> Ja gut, dann bezeichne ich diesen Typen aber mit i, j, k, ...
> und nicht mit x, y, z.
Was ist da der Unterschied? Man kann auch a, b und c nehmen...

von Stefan F. (Gast)


Lesenswert?

>> x*0,1 ist genau das Gleiche wie x/10

> Eben nicht! Selbst bei einem AVR8 besteht ein Unterschied
> zwischen Multiplikation, die mit dem MUL-Befehl verkürzt und
> beschleunigt werden kann, und der Division, die deutlich
> aufwendiger mit Subtraktionen und Bitschieberei erledigt werden muß.

Das wollte ich überprüfen und kam zu einem überraschenden Ergebnis:
1
__attribute__ ((noinline)) uint16_t durch_zehn(uint16_t a)
2
{
3
  return a/10;
4
}
5
6
__attribute__ ((noinline)) uint16_t mal_null_komma_eins(uint16_t a)
7
{
8
  return a*0.1;
9
}

Compiliert mit -O0 erzeugt die Multiplikation deutlich umfangreicheren 
Code:
1
00000080 <durch_zehn>:
2
  80:  cf 93         push  r28
3
  82:  df 93         push  r29
4
  84:  00 d0         rcall  .+0        ; 0x86 <durch_zehn+0x6>
5
  86:  cd b7         in  r28, 0x3d  ; 61
6
  88:  de b7         in  r29, 0x3e  ; 62
7
  8a:  9a 83         std  Y+2, r25  ; 0x02
8
  8c:  89 83         std  Y+1, r24  ; 0x01
9
  8e:  89 81         ldd  r24, Y+1  ; 0x01
10
  90:  9a 81         ldd  r25, Y+2  ; 0x02
11
  92:  9c 01         movw  r18, r24
12
  94:  ad ec         ldi  r26, 0xCD  ; 205
13
  96:  bc ec         ldi  r27, 0xCC  ; 204
14
  98:  0e 94 a5 00   call  0x14a  ; 0x14a <__umulhisi3>
15
  9c:  96 95         lsr  r25
16
  9e:  87 95         ror  r24
17
  a0:  96 95         lsr  r25
18
  a2:  87 95         ror  r24
19
  a4:  96 95         lsr  r25
20
  a6:  87 95         ror  r24
21
  a8:  0f 90         pop  r0
22
  aa:  0f 90         pop  r0
23
  ac:  df 91         pop  r29
24
  ae:  cf 91         pop  r28
25
  b0:  08 95         ret
26
27
000000b2 <mal_null_komma_eins>:
28
  b2:  cf 93         push  r28
29
  b4:  df 93         push  r29
30
  b6:  00 d0         rcall  .+0        ; 0xb8 <mal_null_komma_eins+0x6>
31
  b8:  cd b7         in  r28, 0x3d  ; 61
32
  ba:  de b7         in  r29, 0x3e  ; 62
33
  bc:  9a 83         std  Y+2, r25  ; 0x02
34
  be:  89 83         std  Y+1, r24  ; 0x01
35
  c0:  89 81         ldd  r24, Y+1  ; 0x01
36
  c2:  9a 81         ldd  r25, Y+2  ; 0x02
37
  c4:  cc 01         movw  r24, r24
38
  c6:  a0 e0         ldi  r26, 0x00  ; 0
39
  c8:  b0 e0         ldi  r27, 0x00  ; 0
40
  ca:  bc 01         movw  r22, r24
41
  cc:  cd 01         movw  r24, r26
42
  ce:  0e 94 e3 00   call  0x1c6  ; 0x1c6 <__floatunsisf>
43
  d2:  dc 01         movw  r26, r24
44
  d4:  cb 01         movw  r24, r22
45
  d6:  2d ec         ldi  r18, 0xCD  ; 205
46
  d8:  3c ec         ldi  r19, 0xCC  ; 204
47
  da:  4c ec         ldi  r20, 0xCC  ; 204
48
  dc:  5d e3         ldi  r21, 0x3D  ; 61
49
  de:  bc 01         movw  r22, r24
50
  e0:  cd 01         movw  r24, r26
51
  e2:  0e 94 49 01   call  0x292  ; 0x292 <__mulsf3>
52
  e6:  dc 01         movw  r26, r24
53
  e8:  cb 01         movw  r24, r22
54
  ea:  bc 01         movw  r22, r24
55
  ec:  cd 01         movw  r24, r26
56
  ee:  0e 94 b4 00   call  0x168  ; 0x168 <__fixunssfsi>
57
  f2:  dc 01         movw  r26, r24
58
  f4:  cb 01         movw  r24, r22
59
  f6:  0f 90         pop  r0
60
  f8:  0f 90         pop  r0
61
  fa:  df 91         pop  r29
62
  fc:  cf 91         pop  r28
63
  fe:  08 95         ret


Compiliert mit -O1 erzeugt die Multiplikation immer noch deutlich 
umfangreicheren Code:
1
00000080 <durch_zehn>:
2
  80:  9c 01         movw  r18, r24
3
  82:  ad ec         ldi  r26, 0xCD  ; 205
4
  84:  bc ec         ldi  r27, 0xCC  ; 204
5
  86:  0e 94 70 00   call  0xe0  ; 0xe0 <__umulhisi3>
6
  8a:  96 95         lsr  r25
7
  8c:  87 95         ror  r24
8
  8e:  96 95         lsr  r25
9
  90:  87 95         ror  r24
10
  92:  96 95         lsr  r25
11
  94:  87 95         ror  r24
12
  96:  08 95         ret
13
14
00000098 <mal_null_komma_eins>:
15
  98:  bc 01         movw  r22, r24
16
  9a:  80 e0         ldi  r24, 0x00  ; 0
17
  9c:  90 e0         ldi  r25, 0x00  ; 0
18
  9e:  0e 94 ae 00   call  0x15c  ; 0x15c <__floatunsisf>
19
  a2:  2d ec         ldi  r18, 0xCD  ; 205
20
  a4:  3c ec         ldi  r19, 0xCC  ; 204
21
  a6:  4c ec         ldi  r20, 0xCC  ; 204
22
  a8:  5d e3         ldi  r21, 0x3D  ; 61
23
  aa:  0e 94 14 01   call  0x228  ; 0x228 <__mulsf3>
24
  ae:  0e 94 7f 00   call  0xfe  ; 0xfe <__fixunssfsi>
25
  b2:  cb 01         movw  r24, r22
26
  b4:  08 95         ret

Offensichtlich ist hier in beiden Fällen entscheidend, dass bei der 
Multiplikation eine Fließkommazahl verwendet wurde, bei der Division 
jedoch nur Integer vorkommen.

Da habe ich mal wieder etwas dazu gelernt.

von Gästchen (Gast)


Lesenswert?

Rene K. schrieb:
> Peter D. schrieb:
>> Ich habs grad mal compiliert, itoa() benötigt wahnsinnig enorme, extrem
>> riesige, unvorstellbar gigantische 134 Byte Flash, das sind volle 0,4%
>> Deines ATmega32.
>> Findest Du es nicht selber lachhaft, darum so ein Getöse zu machen?
>
> Das Argument lasse ich gelten :-D Leider muss ich viele Werte umwandeln
> um sie via UART rauszuschicken. In der Summierung macht sich das schon
> bezahlbar ja. Und "Getöse" war es ja nichtmal, ging ja alles flott von
> der Hand und hat mich ja auch zeitlich nicht sonderlich aufgehalten.
>
> Das andere wäre ja auch noch eine Spur einfacher gewesen, ich könnte ja
> auch die Daten direkt rausschicken und auf dem Host die Umrechnung
> machen lassen. Aber so isses schöner, passt, is kleiner und läuft.

Naja.
Ich täte zunächst mal kucken, wo denn die ganze Rechenzeit hinfließt. 
Dazu gibts zum Beispiel die Möglichkeit, mittels Timer zu zählen, 
wieviele Taktzyklen denn eine bestimmte Funktion wirklich benötigt. Oder 
man setzt sich einen Pin, das Scope kann dir DIREKT sagen, wie langer 
der Controller da drin rumgammelt. Gemittelt Minuten wenn es sein muss.

Nur Funktionen, in denen er lange ist, sollte man überhaupt anschauen.

Dabei stellt sich oft heraus, dass eine als wichtig betrachtete 
Optimierung nur im unteren Promillebereich effektiv ist, aber eine 
andere Funtkion wegen eines simplen Fehlers massig Zyklen frisst.

Ein strategisch ungeschickt verwendetes % mir schon mal 20% CPU-Last 
gekostet.

Vor allem stellt sich IMMER heraus, dass das anders ist, als man 
geglaubt hat :-)

Premature optimization is the root of all evil. (Donald Knuth)

von Achim (Gast)


Lesenswert?

x*102/1024

Multiplikation und shift sollten recht schnell gehen.

Sollte, wenn ich mich nicht täusche keinen Rundungsfehler haben.

von Waldo (Gast)


Lesenswert?

Hallo,
wie oft wurde x/10 in diesem Forum schon diskutiert?

Waldo

von Achim (Gast)


Lesenswert?

Keine Rundungsfehler bis x==1024

von m.n. (Gast)


Lesenswert?

Lothar M. schrieb:
> Was ist da der Unterschied? Man kann auch a, b und c nehmen...

Der Unterschied besteht im Programmierstil, der sich in Anlehnung an K&R 
ergeben hat. Eine Character-Variable bekommt 'c', ein String 's', 
Pointer vorzugsweise 'p' und 'q' und eine temporäre Variable 'temp' als 
Bezeichner.
Angelehnt an mathematische Funktionen stellen 'x' und 'y' reelle Zahlen 
dar. Einfaches Beispiel: y = ax + b

Das sollte doch nachvollziehbar sein?

von m.n. (Gast)


Lesenswert?

Stefan U. schrieb:
> Offensichtlich ist hier in beiden Fällen entscheidend, dass bei der
> Multiplikation eine Fließkommazahl verwendet wurde, bei der Division
> jedoch nur Integer vorkommen.
>
> Da habe ich mal wieder etwas dazu gelernt.

Vergleich doch auch noch die Bereechnungen für a *= 10; und a /= 0.1;

;-)

von Jobst Q. (joquis)


Lesenswert?

Stefan U. schrieb:
> Compiliert mit -O1 erzeugt die Multiplikation immer noch deutlich
> umfangreicheren Code:
> 00000080 <durch_zehn>:
> 80:  9c 01         movw  r18, r24
> 82:  ad ec         ldi  r26, 0xCD  ; 205
> 84:  bc ec         ldi  r27, 0xCC  ; 204
> 86:  0e 94 70 00   call  0xe0  ; 0xe0 <__umulhisi3>
...
Siehe da, bei der Division mit konstanter 10 wird auch multipliziert. 
Die Verwendung von float bei Multiplikation mit 0.1  macht es natürlich 
aufwendiger.

Würde mich wundern, wenn das bei itoa nicht auch so gemacht würde.

: Bearbeitet durch User
von Thomas E. (picalic)


Lesenswert?

m.n. schrieb:
> Angelehnt an mathematische Funktionen stellen 'x' und 'y' reelle Zahlen
> dar. Einfaches Beispiel: y = ax + b

Das steht ja jedem frei, es so zu halten, besonders, wenn er z.B. als 
Prof Mathe- oder Informatik-Vorlesungen hält. Wenn ich aber in einer 
Mikrocontroller-Anwendung z.B. in einer Integer-Variablen den Verfahrweg 
in x-Richtung speichern will, benenne ich die Variable deshalb nicht in 
"i" um, da ist mir Mathe und K&R Schnurz...
Und vom Namen auf den Typ zu schließen ist sicher auch nicht im Sinne 
von K&R konsequent.

Daß x/10 anderen Code erzeugt, als x * 0.1 (mit x als int), ist doch 
klar definiert: "0.1" ist eine reelle Zahl, wird also als float 
behandelt, daher wird der 2. Operand immer intern vor der Operation auch 
in float umgewandelt. "10" ist dagegen eine ganze Zahl, folglich wird 
"x/10" als int/int = Interger-Division verarbeitet.

Achim schrieb:
> Keine Rundungsfehler bis x==1024

auch darunter schon: 900 * 102 / 1024 = 89

: Bearbeitet durch User
von Stefan K. (stefan64)


Lesenswert?

m.n. schrieb:
> Der Unterschied besteht im Programmierstil, der sich in Anlehnung an K&R
> ergeben hat. Eine Character-Variable bekommt 'c', ein String 's',
> Pointer vorzugsweise 'p' und 'q' und eine temporäre Variable 'temp' als
> Bezeichner.
> Angelehnt an mathematische Funktionen stellen 'x' und 'y' reelle Zahlen
> dar. Einfaches Beispiel: y = ax + b

Den Typ einer Variablen im Namen zu spiegeln hatte zu Zeiten von K&R 
noch Sinn. Heutzutage liefert so ziemlich jede IDE den Typ einer 
Variablen, sobald der Mauszeiger über ihr steht.
Ein sinnvoller Variablenname soll repräsentieren, WAS in einer Variable 
steht. Ggf. kann dazu die Angabe der Einheit des gespeicherten Werts 
dazukommen.

Viele Grüße, Stefan

von m.n. (Gast)


Lesenswert?

Thomas E. schrieb:
> Wenn ich aber in einer
> Mikrocontroller-Anwendung z.B. in einer Integer-Variablen den Verfahrweg
> in x-Richtung speichern will, benenne ich die Variable deshalb nicht in
> "a" um, da ist mir Mathe und K&R Schnurz...

Mir ist es Schnurz, ob Du Deinen Anfängerfehler bezüglich eines 
Verfahrweges beibehalten willst oder nicht.

Bei mir werden diese Wege als 'float' bzw. 'double' in 'mm' verarbeitet. 
Da ist es dann egal, ob ein Geber 10 µm, 2,5 µm, 0,2 µm oder 0,1µm 
Auflösung hat. Man kann die Werte direkt miteinander verrechnen und bei 
Bedarf ohne Verlust von Genauigkeit/Auflösung auch nach 'inch' wandeln.

Stefan K. schrieb:
> Den Typ einer Variablen im Namen zu spiegeln hatte zu Zeiten von K&R
> noch Sinn. Heutzutage liefert so ziemlich jede IDE den Typ einer
> Variablen, sobald der Mauszeiger über ihr steht.

Dann gehe ich mal davon aus, daß Du die K&R Zeiten nicht miterlebt hast, 
und immer eine IDE mit Mauszeiger in der Tasche durch die Gegend 
schleppst.

von Axel S. (a-za-z0-9)


Lesenswert?

Thomas E. schrieb:
> m.n. schrieb:
>> Angelehnt an mathematische Funktionen stellen 'x' und 'y' reelle Zahlen
>> dar. Einfaches Beispiel: y = ax + b
>
> Das steht ja jedem frei, es so zu halten, besonders, wenn er z.B. als
> Prof Mathe- oder Informatik-Vorlesungen hält.

Im Kontext der Fragestellung "Ich will eine Zahl in die String-
Darstellung umwandeln und muß dafür ja immer wieder durch 10
dividieren" kommt man genau gar nicht auf die Idee, bei dieser
Zahl könnte es sich um einen Fließkommatyp handeln.

Das war eine reine Schutzbehauptung von Mino, um seine dämliche
Aussage "x/10 ist genau das gleiche wie x*0.1" zu retten.

Das Verfahren, suzessive durch 10 zu dividieren und die Divisions-
Reste als Dezimalstellen der Zahl zu verwenden, funktioniert genau
nur für Integer-Zahlen. Bei Fließkomma gibt es ja keinen Rest.


Stefan K. schrieb:
> Den Typ einer Variablen im Namen zu spiegeln hatte zu Zeiten
> von K&R noch Sinn.

IMNSHO hatte diese sogenannte "ungarische Notation" noch nie
irgendeinen Vorteil. Na gut, man konnte die Größe des Quellcodes
etwas aufblähen und so Produktivität vortäuschen ...

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Achim schrieb:
> Sollte, wenn ich mich nicht täusche keinen Rundungsfehler haben.
Der Fehler dieser Rechnung ist etwa -0,4%. Und dieser Fehler wird sich 
natürlich über die anzuzeigenden Ziffern auswirken.

Wenn z.B. 1000 angezeigt werden sollen, dann kommt beim stellenweisen 
Dividieren mit Integern(!) tatsächlich ein Wert von 990 auf dem Display 
heraus:
1
               1000 -> Einer = 0
2
1000*102/1024 -> 99 -> Einer = 9
3
99  *102/1024 ->  9 -> Einer = 9

m.n. schrieb:
> Lothar M. schrieb:
>> Was ist da der Unterschied? Man kann auch a, b und c nehmen...
> Der Unterschied besteht im Programmierstil, der sich in Anlehnung an K&R
> ergeben hat. ....
> Das sollte doch nachvollziehbar sein?
Jetzt nach dieser zweiseitigen Erklärung schon.
Allein: das ist mir zu kompliziert und ich gebe deshalb den Variablen 
einfach solche Namen, die auch ohne Insiderwissen selbsterklärend sind. 
Und ich muss heute nicht mehr an jede Zeichenkette ein s oder ein c oder 
ein ul anhängen, weil sich nämlich die Editoren so weiterentwickelt 
haben, dass sie mir diese "Merkarbeit" abnehmen. Der Editor zeigt mir 
den Datentyp, ich muss ihn nicht mehr in den Variablennamen packen...

> Angelehnt an mathematische Funktionen stellen 'x' und 'y' reelle Zahlen
> dar. Einfaches Beispiel: y = ax + b
Genau diese "Grundschulrechnerei" mit x und y hat uns unser Professor 
seinerzeit am Anfang des ersten Semesters ganz bewusst ausgetrieben. Und 
wenn ich mich nicht irre tauchen auch in einer der Mitternachtsformeln p 
und q auf...

: Bearbeitet durch Moderator
von Stefan K. (stefan64)


Lesenswert?

m.n. schrieb:
> Dann gehe ich mal davon aus, daß Du die K&R Zeiten nicht miterlebt hast,
> und immer eine IDE mit Mauszeiger in der Tasche durch die Gegend
> schleppst.

Ganz im Gegenteil, ich schätze meinen K&R (eine der ersten Ausgaben) 
sehr. Und ebenso schätze ich die Vorzüge moderner 
Entwicklungsumgebungen.

Für die Variablen-Namensgebung ist zuallererst der Projekt Styleguide 
relevant. Die von Dir genannte Namensgebung habe ich bisher aber noch in 
keinem beschrieben gesehen.

Gruß, Stefan

von Timm T. (Gast)


Lesenswert?

Axel S. schrieb:
> Das Verfahren, suzessive durch 10 zu dividieren und die Divisions-
> Reste als Dezimalstellen der Zahl zu verwenden, funktioniert genau
> nur für Integer-Zahlen.

Das Verfahren - welches ich selbst bei gewissen Aufgabenstellungen gern 
anwende - hat einen gravierenden Nachteil: Du bekommst die Ziffern in 
der Reihenfolge Einer-Zehner-Hunderter-Tausender. Für eine Ausgabe per 
RS232 oder Display mußt Du sie also zwischenspeichern und in umgekehrter 
Reihenfolge ausgeben.

Deswegen verwende ich in diesen Fällen gern obige Routine. Da muß die 
While-Schleife für jede Dezimalstelle maximal Neunmal durchlaufen 
werden. Bei einer Softdivision mit Integer läuft jede Stelle schon 16mal 
(Shift durch 16 Bits) durch, zuzüglich Aufrufs der Divisionsroutine und 
Variablenübergabe.

von Leo C. (rapid)


Lesenswert?

Die Konvention, daß alle Variablen, die mit I,J,K,L,M oder N beginnen, 
Interger sind, und alle anderen REAL (float), stammt ursprünglich von 
FORTRAN. Wenn man sich in FORTRAN daran hält, kann man die 
Typvereinbarung weglassen, und spart ein paar Lochkarten.

von Timm T. (Gast)


Lesenswert?

Leo C. schrieb:
> Die Konvention, daß alle Variablen, die mit I,J,K,L,M oder N beginnen,
> Interger sind, und alle anderen REAL (float), stammt ursprünglich von
> FORTRAN.

Ich nehme grundsätzlich nur 1- und 2-stellige Variablennamen in 
Großbuchstaben, weil Basic das so wollte. Und Zeilennummern! Ganz 
wichtig sind Zeilennummern!

von m.n. (Gast)


Lesenswert?

Axel S. schrieb:
> Das war eine reine Schutzbehauptung von Mino, um seine dämliche
> Aussage "x/10 ist genau das gleiche wie x*0.1" zu retten.

Na, schlecht geschlafen letzte Nacht?

> Das Verfahren, suzessive durch 10 zu dividieren und die Divisions-
> Reste als Dezimalstellen der Zahl zu verwenden, funktioniert genau
> nur für Integer-Zahlen. Bei Fließkomma gibt es ja keinen Rest.

Wenn man den ganzzahligen Anteil subtrahiert, kann man auch mit dem Rest 
weiterarbeiten. Aber ich sehe schon, Vielfalft ist out - Monotonie in.

Leo C. schrieb:
> Die Konvention, daß alle Variablen, die mit I,J,K,L,M oder N beginnen,
> Interger sind, und alle anderen REAL (float), stammt ursprünglich von
> FORTRAN.

Oh, vor über 40 Jahren habe ich FORTRAN gemacht; kann sein, daß ich es 
damals verinnerlicht hatte. C war ja erst deutlich später angesagt.

von Axel S. (a-za-z0-9)


Lesenswert?

Timm T. schrieb:
> Axel S. schrieb:
>> Das Verfahren, suzessive durch 10 zu dividieren und die Divisions-
>> Reste als Dezimalstellen der Zahl zu verwenden, funktioniert genau
>> nur für Integer-Zahlen.
>
> Das Verfahren - welches ich selbst bei gewissen Aufgabenstellungen gern
> anwende - hat einen gravierenden Nachteil: Du bekommst die Ziffern in
> der Reihenfolge Einer-Zehner-Hunderter-Tausender. Für eine Ausgabe per
> RS232 oder Display mußt Du sie also zwischenspeichern und in umgekehrter
> Reihenfolge ausgeben.

Ganz recht. Andererseits ist dieser Nachteil vergleichsweise simpel zu 
kompensieren: man schreibt die Dezimalzahlen einfach beginnend vom Ende 
rückwärts in den Buffer (den man für einen String ja ohnehin braucht). 
Schlimmstenfalls muß man den String danach noch einmal kopieren. Der 
Overhead dafür ist vergleichsweise gering - die Division dominiert die 
Laufzeit der Schleife bei weitem. Außer vielleicht bei Architekturen die 
nativ dividieren können.

Der Vorteil des Verfahrens ist, daß man es jedem Anfänger leicht 
erklären kann. Das Gegenbeispiel wäre "Schieben mit BCD-Korrektur" aka 
"double dabble" [1] aka "Dreierkorrektur" [2].

Die Tatsache, daß es jetzt nur noch eine Division mit einer Konstante 
gibt, macht dem Compiler das Leben (die Optimierung) leichter.


[1] was ist das für ein bescheuerter Name?
[2] unter diesem Namen steht es in diversen Fachbüchern hier

von Timm T. (Gast)


Lesenswert?

Axel S. schrieb:
> den man für einen String ja ohnehin braucht

Nope, für die Ausgabe an RS232 oder Display brauchst Du eben gerade 
keinen extra String, wie obige Routine zeigt. Du schmeißt die Zeichen 
einfach einzeln raus. Und bei RS232 wartest Du eh die meiste Zeit aufs 
Senden, wenn Du nicht mit Sendebuffer* und Interrupt arbeitest.

*) Wobei der Sendebuffer hier wieder was anderes als der 
Zeichenkettenstring ist.

von Stefan F. (Gast)


Lesenswert?

> Das war eine reine Schutzbehauptung von Mino, um seine dämliche
> Aussage "x/10 ist genau das gleiche wie x*0.1" zu retten.

Nein, du hast da eine Aussage von MIR (nicht Mino) in den falschen 
Kontext gestellt.

Ich habe behauptet "x/10 ist genau das gleiche wie x*0.1", nachdem 
jemand die Multiplikation als bessere Alternative zur Division empfohlen 
hat.

Nun habe ich allerdings selbst herausgefunden und hier gezeigt, dass 
diese beiden Schreibweisen doch nicht den selben Code ergeben und dass 
die Multiplikation in diesem Fall sogar noch schlechter ist, als die 
Division.

von Waldo (Gast)


Lesenswert?

Hallo,
wenn ich eine Ganzzahl nach ASCII konvertieren will kann ich, wie 
bereits diskutiert:

1.:
sukzessive durch 10 dividieren und den Rest als ASCII Zeichen speichern

2.:
10er Stellen sukzessive durch Subtraktion ermitteln und nach ASCII 
wandeln, hier muss ich mit der grössten Stelle anfangen

Auf den ersten Blick ist die erste Methode elegant und kompakt. Ohne 
Divisionsbefehl, der das Ergebnis mit Rest liefert, wird das ganze 
jedoch kompliziert. Man braucht eine Näherung für x/10, die für alle 
Werte von x genau ist und man muss den Rest auch noch bilden.
der Ansatz:
x/10 = x*26/256 ist genau bis x=68
x/10 = (x*25+x/2+x/8)/256 ist genau bis x=1048
...
Und den Rest muss man bilden mit r=x-div(x,10)*10.

Ich denke also die Methode sukzessive zu Subtrahieren ist besser als man 
denkt.

Waldo

von Timm T. (Gast)


Lesenswert?

Waldo schrieb:
> Ich denke also die Methode sukzessive zu Subtrahieren ist besser als man
> denkt.

Ja, ich dachte auch erst: Das ist ja billig. Aber es ist sehr flexibel 
auf verschiedene Stellenzahlen, Nachkommastellen, mit und ohne Leading 
Zero usw. anpaßbar.

Double Dabble gefällt mir, aber ist schwerer durchschaubar und damit 
fehleranfällig, wenn man es anpassen muß. Und es benötigt die 
Zwischenspeicherstellen, nachträgliches Extrahieren aus den Nibbles und 
Wandeln von BCD zu ASCII.

von Waldo (Gast)


Lesenswert?

zu x*102/1024:

mit x=10

x*10/1024 = 1020/1024 = 0

liefert 126 Fehler bis x=255

Waldo

von Waldo (Gast)


Lesenswert?

Sorry,
liefert 25 Fehler bis 255.

Waldo

von Axel S. (a-za-z0-9)


Lesenswert?

Timm T. schrieb:
>> den man für einen String ja ohnehin braucht
>
> Nope, für die Ausgabe an RS232 oder Display brauchst Du eben gerade
> keinen extra String, wie obige Routine zeigt. Du schmeißt die Zeichen
> einfach einzeln raus.

Ich halte es für extrem schlechten Stil, Konvertierung und Ausgabe 
derart "verzahnt" zu implementieren. IMNSHO gehört die Konvertierung in 
eine extra Funktion (itoa läßt grüßen). Und dann muß der Rückgabewert 
irgendwo zwischengespeichert werden.


Waldo schrieb:
> Ich denke also die Methode sukzessive zu Subtrahieren ist besser
> als man denkt.

Sie skaliert halt nicht so gut für große Zahlen. Überhaupt muß man den 
möglichen Umfang des Wertebereichs vorher kennen; und wehe, wenn die 
übergebene Zahl größer ist als die Routine erwartet. Man sollte hier 
keine Abkürzung vornehmen und entweder den gesamten Wertebereich des 
Argumenttyps abdecken oder zumindest auf Überschreitung des 
Wertebereichs testen.

Die Variante mit der Division paßt sich ganz von selber an den Werte- 
bereich an. Und sie ist trivial auf eine andere Zahlenbasis umzustellen.

Ich glaube statt dessen, der Aufwand der Division/Modulus-Operation wird 
notorisch überschätzt.

von Stefan F. (Gast)


Lesenswert?

> Ich halte es für extrem schlechten Stil, Konvertierung und
> Ausgabe derart "verzahnt" zu implementieren.

Andere Leute halten es für schlechten Stil, bei Mikrocontrollern 
Speicher zu vergeuden.

von Jobst Q. (joquis)


Lesenswert?

Axel S. schrieb:
> Ich glaube statt dessen, der Aufwand der Division/Modulus-Operation wird
> notorisch überschätzt.

Eine echte Division mit 2 Unbekannten ist schon recht aufwendig. Aber 
eine Division durch eine Konstante wird von guten Compilern eh durch 
Multiplikation und Shiften ersetzt. Siehe oben.

von Tom (Gast)


Lesenswert?

Andere halten es für schlechten Stil, aufgrund von irgendwelchem rein 
gefühlten Optimierungsbedarf eine simple Division mit viel Arbeitszeit 
in die Unwartbarkeit zu "optimieren", ohne belegen zu können, dass sich 
das lohnt.

Und alle diese Sichtweisen sind Religionen, deshalb bringt jede 
Diskussion rein gar nichts, außer dass alle Teilnehmer sich hinterher 
gegenseitig für Idioten halten.

von Bernd K. (prof7bit)


Lesenswert?

Hier ist für jeden was dabei:
http://www.hackersdelight.org/divcMore.pdf

: Bearbeitet durch User
von m.n. (Gast)


Lesenswert?

Axel S. schrieb:
> Ich halte es für extrem schlechten Stil, Konvertierung und Ausgabe
> derart "verzahnt" zu implementieren. IMNSHO gehört die Konvertierung in
> eine extra Funktion (itoa läßt grüßen). Und dann muß der Rückgabewert
> irgendwo zwischengespeichert werden.

Wem soll man es denn nun recht machen?
Programmiert man sauber und alles schön getrennt (womöglich noch mit 
'float'-Zahlen), wird man angemacht, den µC gandenlos zu überlasten.

Programmiert man 'verzahnt', was für den Ablauf eines Programmes sehr 
bechleunigend werden kann, wird man angemacht, keine Struktur im 
Programm zu haben.

Im vorliegenden Fall kann ich Timms Ansicht nur bekräftigen. Zum einen 
werden die Zeichen von MSD nach LSD gewandelt und können verzahnt per 
UART aber auch auf ein LCD ausgegeben werden. Gerade bei Letzterem 
erspart man sich die 40-50 µs Wartezeit/Zeichen bei der Ausgabe.

von Dirk B. (dirkb2)


Lesenswert?

Stefan U. schrieb:
>>> Für a=b/2 und a=b<<1 erzeugt der Compiler exakt den selben Bytecode.
>> Bestimmt nicht.
>
> Sorry, die Pfeile sind natürlich falsch herum.

Wenn b signed ist und der Compiler mit Zweierkomplement rechnet, darf er 
das nicht machen.

Für z.B. b = -3 ergibt b/2 das erwartete -1
und bei b>>1 kommt -2 heraus.

von Stefan F. (Gast)


Lesenswert?

> Wenn b signed ist

Es geht um unsigned Integer. Außerdem bist du nicht der erste, der 
darauf hinweist.

Es wurde alles mehrfach gesagt, nur noch nicht von jedem.

von Timm T. (Gast)


Lesenswert?

Axel S. schrieb:
> Ich halte es für extrem schlechten Stil, Konvertierung und Ausgabe
> derart "verzahnt" zu implementieren.

Ich halte es für extrem schlechten Stil, im µC ineffizient zu 
programmieren.

Axel S. schrieb:
> Sie skaliert halt nicht so gut für große Zahlen. Überhaupt muß man den
> möglichen Umfang des Wertebereichs vorher kennen

Wenn ich im µC mit Ganzzahlen / Festkommazahlen arbeite, muß ich IMMER 
darauf achten, in welchem Wertebereich ich mich bewege.

Und was das Skalieren angeht: Eine Long-Division in Software skaliert 
besser als eine Subtraktion mit 4 Bytes? Wohl kaum.

von Paul B. (paul_baumann)


Lesenswert?

Waldo schrieb:
> Hallo,
> wie oft wurde x/10 in diesem Forum schon diskutiert?

Schon X-mal...

MfG Paul

von Michael W. (Gast)


Lesenswert?

Draco schrieb:
> Gibt es eine
> bessere Alternative als ein x/10? Vielleicht ein bitshift mit
> aufaddieren?

Mal 1.6 und durch 16 Teilen?

von Axel S. (a-za-z0-9)


Lesenswert?

Timm T. schrieb:
> Axel S. schrieb:
>> Ich halte es für extrem schlechten Stil, Konvertierung und Ausgabe
>> derart "verzahnt" zu implementieren.
>
> Ich halte es für extrem schlechten Stil, im µC ineffizient zu
> programmieren.

Das ist noch nicht raus, ob das wirklich ineffizient ist. Ich habe 
letzthin z.B. viel µC Code geschrieben, wo die gleiche Ausgabe einmal 
lokal auf das LCD und einmal per UART an den PC geht. An dieser Stelle 
wäre es ineffizient, die Konvertierung zweimal zu machen.

Es kommt immer auf das Umfeld an. Aber eine Konvertierungsfunktion a'la 
itoa() hat zumindest den Vorteil, universell zu sein.

>> Sie skaliert halt nicht so gut für große Zahlen. Überhaupt muß man den
>> möglichen Umfang des Wertebereichs vorher kennen
>
> ... was das Skalieren angeht: Eine Long-Division in Software skaliert
> besser als eine Subtraktion mit 4 Bytes? Wohl kaum.

Die Division muß man nur einmal pro Dezimalstelle machen. Die 
Subtraktion bis zu neunmal. Bei der Laufzeit wird sich das nicht viel 
nehmen, bei der Codegröße gewinnt mit Sicherheit die Division. Mit um so 
mehr Abstand, je größer die Zahlen werden.

Aber falls das so rüber gekommen sein sollte: ich will auf keinen Fall 
die Methode des suzessiven Dividierens als silver bullet hinstellen. 
Allein schon deswegen, weil es so etwas gar nicht gibt. Was die beste 
Lösung ist, variiert mit der konkreten Aufgabe und der konkreten 
Hardware.

von Paul B. (paul_baumann)


Lesenswert?

Markus W. schrieb:
> Mal 1.6 und durch 16 Teilen?

Ach was! Nägel mit Köpfen machen und durch NULL teilen. Dann sieht man 
wenigstens, ob der Kompiler fehlertolerant ist.

SCNR
Paul

von Timm T. (Gast)


Lesenswert?

Axel S. schrieb:
> Die Division muß man nur einmal pro Dezimalstelle machen. Die
> Subtraktion bis zu neunmal.

Oha. Du weißt aber schon, was bei einer Software-Division passiert?

Ich verrate nur so viel: Schleife und jedes Bit darf mal vor.

von Possetitjel (Gast)


Lesenswert?

Timm T. schrieb:

> Axel S. schrieb:
>> Die Division muß man nur einmal pro Dezimalstelle machen. Die
>> Subtraktion bis zu neunmal.
>
> Oha. Du weißt aber schon, was bei einer Software-Division passiert?
>
> Ich verrate nur so viel: Schleife und jedes Bit darf mal vor.

Ahh. Es hat noch jemand gemerkt. Sehr schön.

von c-hater (Gast)


Lesenswert?

Axel S. schrieb:

> Ich halte es für extrem schlechten Stil, Konvertierung und Ausgabe
> derart "verzahnt" zu implementieren.

Warum sollte das schlecht sein? Wenn eh' nur zur Ausgabe diese 
Konvertierung nötig ist (der absolute Regelfall, denn wer rechnet schon 
mit Zahlen in dezimaler ASCII-Repräsentation!!!), dann wäre es sogar 
extrem dumm, Speicher und Rechenzeit zu verschwenden, nur um das zu 
formal zu trennen.

Natürlich gibt es Anwendungsfälle, wo es trotzdem sinnvoll ist, das zu 
trennen, z.B. wenn eine tabellierte Ausgabe wünschenswert ist. Dann tut 
man es halt, aber eben nur dann, wenn sich daraus auch ein sachlicher 
Vorteil ergibt, und nicht nur, um irgendeiner mehr oder weniger 
idiotischen "Stil"-Vorgabe zu genügen...

"Form follows function". Das ist die einzig akzeptable Stilvorgabe.

von Timm T. (Gast)


Lesenswert?

c-hater schrieb:
> Natürlich gibt es Anwendungsfälle, wo es trotzdem sinnvoll ist, das zu
> trennen, z.B. wenn eine tabellierte Ausgabe wünschenswert ist.

Auch da und gerade da. Zum Bleistift habe ich bei meiner 
Heizungssteuerung alle Temperaturen als Festpunktzahl mit einer 
Dezimalstelle gespeichert. Für jede Temperatur, die auf dem Display 
dargestellt wird, wird dann die gleiche Routine aufgerufen, die die 
Gleitpunktzahl auseinandernimmt, in ASCII wandelt, führende Nullen durch 
Leerzeichen ersetzt (damit die Position auf dem Display stimmt) und ein 
°C dranhängt. Dieser Routine muß ich nur den Wert übergeben und bekomme 
das Ergebnis aufs Display. Wenn ich das erst über itoa, String usw. 
machen wollte, wäre das deutlich umständlicher.

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.