www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Multiplikation mit 2,56


Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

ich stehe gerade auf dem Schlauch!

Wie kann ich eine Zahl am einfachsten (Ressourcenschonend) mit 2,56 
multiplizieren?

(Ich programmiere den ATmega48)

Autor: Michael Wilhelm (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
var2 = var1 << 2;
var2 += var1 >> 1;
var2 += var1 >> 4;

Schau mal ob dir die Genauigkeit ausreicht.

MW

Autor: Lupin (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Michael wie soll das funktionieren wenn du im ersten schritt var1 schon 
mal 4 nimmst?

Ich würde einfach stumpf wie folgt vorgehen:
ergebnis = (zahl<<8)/100;

Autor: Interessierter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
vielleicht mit 256 multiplizieren und dann (anstatt der Division durch 
100) Zahl aufteilen in ganze Zahl und Dezimalstellen?!?
Also die letzten beiden Ziffern sind Dezimalzahlen, die ersten (wieviel 
auch immer) die ganzen Zahlen.
Die dann so verbasteln wie du es brauchst.....
Wäre meine bescheidene Meinug dazu

Autor: Michael Wilhelm (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tippfehler nur << 1, also mal 2.

MW

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>var2 = var1 << 2;
>var2 += var1 >> 1;
>var2 += var1 >> 4;

>Schau mal ob dir die Genauigkeit ausreicht.

==> var2 = var1 * 2.5625

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke für die Antworten!

Ja, so könnte ich es machen Michael, die Genauigkeit ist für diesen 
Zweck ausreichend. var << 2 hatte ich auchschon als tippfehler 
ausgeschlossen

Danke für den "Schubs" vom Schlauch

Autor: Lupin (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Oder:
ergebnis = (zahl * 655) >> 8;

das ist aber ein bischen ungenau. Die multiplikation lässt sich dafür in 
folgendes zerlegen:

(zahl * 656) = (zahl<<9) + (zahl<<7) + (zahl<<4)

Das ganze dann noch kürzen und man kommt auf:
ergebnis = ((zahl<<5) + (zahl<<3) + zahl) >> 4;

Das entspricht einer Multiplikation mit 2,5625 und nicht 2,56

Natürlich sind die Nachkommastellen durch >> 4 weg. Aber wir wollen ja 
nicht mit fließkommazahlen arbeiten oder?

Autor: RainerSp (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
var2 = var1*4 + var1/2 + var1/16 = var1*73/16 ~ var1*4,75.

Wenn Dir die Genauigkeit reicht, dann nimm gleich mal drei. Das ist dann 
sowas wie pi=3.

Gemeint war vielleicht folgendes:
var2 = var1*2 + var1/2 + var1/16 = var1*2.5625

Autor: Lupin (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tja jetzt verstehe ich michaels antwort auch... :-)

Meine zeile macht das gleiche ist aber bischen doof.

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Herzlichen Dank an alle für die vielfältigen Lösungen!

So stell ich mir ein Forum vor!

(Das mein ich ernst)

Autor: eProfi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Achtung! Vorsicht!
Da bei einem Eingangsbereich von 8 Bit (0..255) das Zwischenergebnis 
(*655) nicht mehr in in 16 Bit passt, muss sowieso mit 32 Bit gerechnet 
werden (außer man macht 24 Bit mit Assembler).

Da kann man auch mit größeren Zahlen erweitern, um genauer zu werden:

erg = ( (uint32_t)zahl * 41943L) >> 14;

Das geht dann auch noch mit 16 Bit Eingangsbereich.

(Auf-)Runden wäre doch auch noch was:
erg = (((uint32_t)zahl * 41943L)+(1L<<13)) >> 14;
oder anders gesagt:
erg = (zahl * 41943L + 8192) / 16384;

Zum Test mit Eingangswert 50000 * 2,56 = 128000
 50000*9          /4    =112500
 50000*41         /16   =128125
 50000*655        /256  =127929,6875 ==> 127929
(50000*655  + 128)/256  =127930,1875 ==> 127930
 50000*41943      /16384=127999,8779 ==> 127999
(50000*41943+8192)/16384=128000,3779 ==> 128000

Wenn Du den Wert darstellen (=in einzelne Ziffern umwandeln) willst, 
bietet sich dafür Peter Daneggers Subtraktions/Additionsroutine an.

Wenn Du dort statt z.B. 10000 10000/2,56=3906{,25} einsetzt, kannst Du 
Dir die vorherige o.g. Multiplikation sparen.
Den Quellcode dieses Tricks muss ich mal suchen (habe ich schonmal vor 
langer Zeit hier gepostet / angehängt).



Mehr Genauigkeit mit Schieben / Addieren:
 50000*2+50000/2+50000/16          =128125
 50000*2+50000/2+50000/16-50000/512=128125- 97=128028
genau wäre:
 50000*2+50000/2+50000/16-50000/400=128125-125=128000



Wenn's nur 256/512/1024 Eingangswerte sein sollen, auch an eine Tabelle 
(const progmem) denken,
kostet 1/4 bis 2 KB Flash / EEprom (je nach dem ob Byte oder Word) und 
ist super schnell.

Die Tabelle kann auch gleich die Digits enthalten, dann erübrigt sich 
die Wandlung in einzelne Ziffern.
z.B. const uint16_t tabelle[256] 
progmem={0x0000,0x0012,0x3456,0x7890,...};
danach einfach die Nibbles=Digits extrahieren, ein Komma reinschmuggeln 
und anzeigen:

uint_16t tmp;
display('0'+ (tmp=tabelle[zahl])/4096);
display(',');
display('0'+((tmp/256)&15));
display('0'| (tmp/ 16)&15 );//bei | statt + eine Klammer weniger 
notwendig
display('0'|  tmp     &15 );

Da hier die Bitauswertung noch nicht optimal ist, kann man auf 
4,5-Stellen (00000..39999 oder -19999..+19999) verbessern:


unsigned char tab2[128]={
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,
0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,
0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,
0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,
0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,
0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,
0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,
0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,
0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,
0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,
0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,//should never be used
0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,
0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7};


display('0'| (tmp=tab1[zahl])/16384);
display('0'| (tmp2=tab2[tmp/128])/16);
display('0'|  tmp2 &15);
display('0'| (tmp2=tab2[tmp&127])/16);
display('0'|  tmp2 &15);


tab1 ist etwas komplizierter, mache ich später fertig:
unsigned int tab1[1024]={
0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007,0x0008,0x0009,
0x000a,0x000b,0x000c,0x000d,0x000e,0x000f,0x0010,0x0011,0x0012,0x0013,
0x0014,0x0015,0x0016,0x0017,0x0018,0x0019,0x001a,0x001b,0x001c,0x001d,
0x001e,0x001f,0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027,
0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f,0x0030,0x0031,
0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,0x0038,0x0039,0x003a,0x003b,
0x003c,0x003d,0x003e,0x003f,0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,
0x0046,0x0047,0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f,
0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,0x0058,0x0059,
0x005a,0x005b,0x005c,0x005d,0x005e,0x005f,0x0060,0x0061,0x0062,0x0063,
0x0064,0x0065,0x0066,0x0067,0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,
0x006e,0x006f,0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077,
0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x007f,
...

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.