Forum: Mikrocontroller und Digitale Elektronik Formel oder Rechenweg gesucht.


von Peter N. (alv)


Lesenswert?

Hi

Ich stehe etwas auf dem Schlauch, vielleicht kann mir jemand den Weg 
weisen?

Ich habe eine Eingangszahl.
Jedem Bit dieser Zahl ist ein bestimmter Wert zugeordnet.

Z.B:
Bit0 -> 0,3
Bit1 -> 0,8
Bit2 -> 1,5
Bit3 -> 2,2

Alle Werte, deren Bits in der Eingangszahl gesetzt sind, sollen einfach 
zur Ausgangszahl zusammenaddiert werden.

Also Eingangszahl = 5 (Binär 0101) => Ausgangszahl 1,8 (1,5+0,3).
Oder Eingangszahl = 14 (Binär 1110) => Ausgangszahl 4,5 (2,2+1,5+0,8).

von Michael B. (laberkopp)


Lesenswert?

1
float Summe=0.0;
2
if(Eingangszahl&1) Summe+=0.3;
3
if(Eingangszahl&2) Summe+=0.8;
4
if(Eingangszahl&4) Summe+=1.5;
5
if(Eingangszahl&8) Summe+=2.2;

?

: Bearbeitet durch User
von Percy N. (vox_bovi)


Lesenswert?

Ja, und?

von Sebastian R. (sebastian_r569)


Lesenswert?

1
Summe = ((Eingang&1)*0.3) + ((Eingang&2)*0.8) + ((Eingang&4)*1.5) + ((Eingang&8)*2.2)

Aber das geht sicherlich noch eleganter...

: Bearbeitet durch User
von Michael B. (laberkopp)


Lesenswert?

Sebastian R. schrieb:
> Aber das geht sicherlich noch eleganter...

Vor allem auch richtiger ... (lass mal rechnen).

von Sebastian R. (sebastian_r569)


Lesenswert?

Michael B. schrieb:
> Vor allem auch richtiger ... (lass mal rechnen).

Mist, ja. Man müsste noch shiften. Damit bleibt deine Antwort wohl die 
Nachvollziehbarste.

von Martin S. (mmaddin)


Lesenswert?

Sebastian R. schrieb:
> ((Eingang&2)*0.8) + ((Eingang&4)*1.5) + ((Eingang&8)*2.2)

shiften vergessen

von Michael B. (laberkopp)


Lesenswert?

Martin S. schrieb:
> shiften vergessen

Ich seh' jetzt nicht die Korrektur, na ja, kann ja noch kommen.

von Sebastian R. (sebastian_r569)


Lesenswert?

Michael B. schrieb:
> Ich seh' jetzt nicht die Korrektur, na ja, kann ja noch kommen.

Nö. Wir nehmen einfach deinen Vorschlag und fertig.

Beitrag #7397401 wurde vom Autor gelöscht.
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Ich würde es in "Zehntel" mit Integern rechnen:
1
int Summe=0;
2
if(Eingangszahl&1) Summe+= 3;
3
if(Eingangszahl&2) Summe+= 8;
4
if(Eingangszahl&4) Summe+=15;
5
if(Eingangszahl&8) Summe+=22;
Das ist schneller und wenns denn unbedingt sein muss, kann man das 
Ergebnis ja immer noch in den Floatwert umrechnen. Mit ein wenig 
Nachdenken kann man solche Floatrechnungen aber oft umgehen.

: Bearbeitet durch Moderator
von Kay-Uwe R. (dfias)


Lesenswert?

Lothar M. schrieb:
> Das ist schneller ...
Und am schnellsten so:
1
float fConvert (uint8_t uiEingangswert)
2
{
3
  static const float f0 =  .3,
4
                     f1 =  .8,
5
                     f2 = 1.5,
6
                     f3 = 2.2,
7
  afTable[] = {          0,
8
                        f0,
9
                     f1   ,
10
                     f1+f0,
11
                  f2      ,
12
                  f2   +f0,
13
                  f2+f1   ,
14
                  f2+f1+f0,
15
               f3         ,
16
               f3      +f0,
17
               f3      +f1,
18
               f3   +f1+f0,
19
               f3+f2      ,
20
               f3+f2   +f0,
21
               f3+f2+f1   ,
22
               f3+f2+f1+f0};
23
24
  return afTable[uiEingangswert & 0xf];
25
} // fConvert

: Bearbeitet durch User
von Andreas B. (bitverdreher)


Lesenswert?

So?
1
float num[4]= {0.3, 0.8, 1.5, 2.2};
2
float sum= 0;
3
uint8_t zahl;
4
5
for (i=0; i<8, i++) {
6
  if (( (zahl>>i) & 0x01)==1) sum+= num[i]; 
7
}

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


Lesenswert?

Kay-Uwe R. schrieb:
> Und am schnellsten so:
Eine LUT ist bei 16 Werten tatsächlich auch ein guter Ansatz.
Den Index 10 hätte ich aber schöner formatiert... ;-)

Oder gleich richtig obfuscated:
1
    afTable[] = {0,f0,f1,f1+f0,f2,f2+f0,f2+f1,f2+f1+f0,f3,f3+f0,f3+f1,f3+f1+f0,
2
f3+f2,f3+f2+f0,f3+f2+f1,f3+f2+f1+f0};

Andreas B. schrieb:
> So?
> for (i=0; i<8, ... num[i];
Amoklaufender Pointer: num hat nur 4 Elemente, der Index selektiert 8.
War aber auch schon recht spät...

: Bearbeitet durch Moderator
von Martin S. (mmaddin)


Lesenswert?

Lothar M. schrieb:
> Eine LUT ist bei 16 Werten tatsächlich auch ein guter Ansatz.

aber nicht als float, etwas oversized...

von Martin S. (mmaddin)


Lesenswert?

Michael B. schrieb:
> Ich seh' jetzt nicht die Korrektur, na ja, kann ja noch kommen.

Summe = ((Eingang&1)*0.3) + (((Eingang&2)/2)*0.8) + 
(((Eingang&4)/4)*1.5) + (((Eingang&8)/8)*2.2);

von Kay-Uwe R. (dfias)


Lesenswert?

Man kann die LUT auch mit einer Initialisierungsroutine bestimmen und 
die Gewichtungen dort als Parametersatz mitgeben. So wären 
(niederfrequente) Änderungen zur Laufzeit möglich:
1
static float afTable[16] = {};
2
3
void vTableInit (float *pfWeights)
4
{
5
  for (int i = 0; i < 16; i++)
6
    afTable[i] = ((i & 1) ? pfWeights[0] : 0)
7
               + ((i & 2) ? pfWeights[1] : 0)
8
               + ((i & 4) ? pfWeights[2] : 0)
9
               + ((i & 8) ? pfWeights[3] : 0);
10
} // vTableInit
11
12
float fConvert (uint8_t uiEingangswert)
13
{
14
  return afTable[uiEingangswert & 0xf];
15
} // fConvert

von Kay-Uwe R. (dfias)


Lesenswert?

Martin S. schrieb:
> Lothar M. schrieb:
>> Eine LUT ist bei 16 Werten tatsächlich auch ein guter Ansatz.
>
> aber nicht als float, etwas oversized...
Was denn? 16 floats sind 64 Byte groß. Das ist ggf. kürzer als ein 
Programm. Und ints sind bei einer 32-Bit-Maschine gleichgroß.
Ich würde hier bis mindestens zu einer 256er-LUT gehen. Für 
16-Bit-Eingangswerte dann auf zwei 256er-LUTs splitten und Low- und 
High-Byte-Anteile addieren. Für 32 Bit analog 4 LUTs.

von Rainer W. (rawi)


Lesenswert?

Kay-Uwe R. schrieb:
> Was denn? 16 floats sind 64 Byte groß.

Der Unfug bei Floats ist die für jede Addition zusätzlich erforderliche 
Hin- und Hershifterei. Nicht jedem ist der Rechenaufwand egal.

von Kay-Uwe R. (dfias)


Lesenswert?

Rainer W. schrieb:
> Der Unfug bei Floats ist die für jede Addition zusätzlich erforderliche
> Hin- und Hershifterei. Nicht jedem ist der Rechenaufwand egal.
Barrel-Shifter und Co-Prozessoren wurden aber schon erfunden, oder? Wenn 
die Vorgabe Floats sind, dann sind das eben Floats. Umso mehr sind daher 
LUTs angesagt. Da gibt es nur load und store.

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


Lesenswert?

Kay-Uwe R. schrieb:
> Wenn die Vorgabe Floats sind
Meine langjährige Erfahrung: wer so eine Frage stellt, verwendet Floats 
nicht unbedingt deshalb, weil er sie für die Aufgabe auch tatsächlich 
braucht. Siehe meinen ersten Post zu diesem Thema...

von Martin S. (mmaddin)


Lesenswert?

Lothar M. schrieb:
> weil er sie für die Aufgabe auch tatsächlich
> braucht.

jup

Kay-Uwe R. schrieb:
> Was denn? 16 floats sind 64 Byte groß.

alles gut, war nicht böse gemeint.

16 uint8_t brauchen 16 Bytes, rechnen können wir :-)

Einfach 3,8,15 und 22 in Ihren Summen in die LUT und erst am ende einen 
schönen float draus machen, wenn überhaupt wirklich nötig...

von Rainer W. (rawi)


Lesenswert?

Kay-Uwe R. schrieb:
> Barrel-Shifter und Co-Prozessoren wurden aber schon erfunden ...
Was erfunden wurde, ist spätestens dann egal, wenn es um einen konkreten 
µC geht. Dann kommt es nämlich nur darauf an, wie dieser konkrete µC 
HW-mäßig ausgestattet ist und was per SW emuliert werden muss.
Aber noch geht es ja nur darum, Peter vom Schlauch herunter zu helfen.
Ob irgendwelcher Optimierungsaufwand lohnt, hängt sowieso von der 
konkreten Anwendung bzw. vom sportlichen Ehrgeiz ab.

von Kay-Uwe R. (dfias)


Lesenswert?

Martin S. schrieb:
> Einfach 3,8,15 und 22 in Ihren Summen in die LUT und erst am ende einen
> schönen float draus machen, wenn überhaupt wirklich nötig...
Und dann wird statt 0.3 auf einmal 0.31841 und statt 0.8 0.79876 
verlangt - und dann?
Hier steht ausdrücklich "zum Beispiel":
Peter N. schrieb:
> Z.B:
> Bit0 -> 0,3
> Bit1 -> 0,8
> Bit2 -> 1,5
> Bit3 -> 2,2

von Rainer W. (rawi)


Lesenswert?

Kay-Uwe R. schrieb:
> Und dann wird statt 0.3 auf einmal 0.31841 und statt 0.8 0.79876
> verlangt - und dann?

Bei Addition Besitz eine Ganzzahl bei gleicher Größe im Speicher immer 
noch mehr gültige Stellen als Float, wenn sie geeignet normiert ist.

von Apollo M. (Firma: @home) (majortom)


Lesenswert?

... two cents more.
1
float calculateVal(uint8_t num) {
2
  const float data[4]= {0.3, 0.8, 1.5, 2.2};
3
  float sum= 0;
4
  for (uint8_t i=0; i!=4; num>>=1,i++) {
5
    if (num & 0x01) sum += data[i]; 
6
  }
7
}

Andreas B. schrieb:
> So?

... variable shifting is ugly and time/code space consuming!

: Bearbeitet durch User
von Andreas B. (bitverdreher)


Lesenswert?

Lothar M. schrieb:
> Amoklaufender Pointer: num hat nur 4 Elemente, der Index selektiert 8.
> War aber auch schon recht spät...

Es ging ums Prinzip. Weder hat er die Groesse des Parameters angegeben 
(koennte ja auch int32 sein), noch die Laenge des float array 
festgelegt.

Apollo M. schrieb:
> ... variable shifting is ugly and time/code space consuming!

Wer sagt das? Unter welcher Platform soll das so sein?

von Apollo M. (Firma: @home) (majortom)


Lesenswert?

Andreas B. schrieb:
> Unter welcher Platform soll das so sein?

Signifikant und getestet unter AVR/GCC, PIC/xc8, ARM/Keil Plattform ...
Probier es mal selber aus aus und schau dir code size/run time an.

: Bearbeitet durch User
von Andreas B. (bitverdreher)


Lesenswert?

Apollo M. schrieb:
> Probier es mal selber aus aus und schau dir code size/run time an.

Mach ich mal bei Gelegenheit. Aber wundern wuerde mich das schon. Jede 
CPU hat eine simple Shift operation.

von Apollo M. (Firma: @home) (majortom)


Lesenswert?

Andreas B. schrieb:
> Jede CPU hat eine simple Shift operation.

Das ist klar und sicher, aber eine variable extra loop (mit shift) ist 
ungünstig, wenn das auch ohne geht.
In den AVR/Tiny Cores von Spence Konde wurde die Arduino Standard 
shiftout/in() Funktion entspr. meinem Vorschlag ersetzt. Spence Konde 
hat zuvor umfangreich detailierte Tests durchgeführt und weitere 
Varianten erprobt. Ziel war maximal shift speed.

von Martin S. (mmaddin)


Lesenswert?

Andreas B. schrieb:
> Wer sagt das?

Rainer W. schrieb:
> gleicher Größe im Speicher immer
> noch mehr gültige Stellen als Float

Wenn wir schon dabei sind, und was heißt das hier? Was sind "gültige 
Stellen im Speicher"?

oder das:

Rainer W. schrieb:
> geeignet normiert ist

?

von Rainer W. (rawi)


Lesenswert?

Martin S. schrieb:
> Wenn wir schon dabei sind, und was heißt das hier? Was sind "gültige
> Stellen im Speicher"?

Bei einem Float nach IEEE 754 mit 32 Bit stehen für die Ziffern 23 Bit 
zur Verfügung - der Rest geht für Vorzeichen und Exponent drauf.
https://de.wikipedia.org/wiki/Gleitkommazahl#Speicherformate

Bei einer Ganzzahl von 32 Bit stehen für die Ziffern bis zu 31 Bit zur 
Verfügung (ein Bit von den 32 fürs Vorzeichen).
Wenn man die Ganzzahl also optimal normiert, hat man 8 Bit mehr für 
gültige Stellen zur Verfügung, also ein Faktor 256 mehr in der 
Auflösung.

Martin S. schrieb:
> Rainer W. schrieb:
>> geeignet normiert ist
> ?

https://de-academic.com/dic.nsf/dewiki/1029361

: Bearbeitet durch User
von Achim M. (minifloat)


Lesenswert?

Peter N. schrieb:
> Ich habe eine Eingangszahl.
> Jedem Bit dieser Zahl ist ein bestimmter Wert zugeordnet.
> Z.B:
> Bit0 -> 0,3
> Bit1 -> 0,8
> Bit2 -> 1,5
> Bit3 -> 2,2

Für mich sieht das irgendwie aus, als wären es...
* nicht 0,3 sondern 0,4
* nicht 1,5 sondern 1,6

...was die Sache vielleicht einfacher macht.

mfg mf

: Bearbeitet durch User
von Philipp K. (philipp_k59)


Lesenswert?

Man könnte auch über die Abstände als Ganzzahl rechnen..

Bit0->+3
Bit1->+5
Bit2->+7
Bit3->+7

Das bleibt eine kleine Lutz, da geht auch noch mehr für Optimierung.

von Bruno V. (bruno_v)


Lesenswert?

Philipp K. schrieb:
> Man könnte auch über die Abstände als Ganzzahl rechnen..

Das würde für ein anderes Problem (Ganzzahl) in anderen Fällen (mehr 
Punkte) mit speziellen Randbedingungen (kein Abstand> 8 oder 16 Bit) 
Speicherplatz sparen können. Zulasten von Laufzeit und Code. Hier sehe 
ich keinen Vorteil zur Kiss-Lösung

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.