Forum: Mikrocontroller und Digitale Elektronik 16Bit auf 100 normieren?


von dieter kuhn (Gast)


Lesenswert?

Hallo zusammen.

Ich habe einen 16Bit Nachkommawert von einer 16Bit Division. Ich möchte 
den Nachkommawert gern auf 100 oder 1000 normieren.

Also für 0 will ich 0 erhalten.
Und für 65535 möchte ich 100 oder 1000 bzw. noch besser 99 oder 999 
erhalten.
Wie bekommt man das elegant hin?

von ... (Gast)


Lesenswert?

Schlechter Plan. Für Rechnung im µC sind 2er-Potenzen immer praktischer 
zu rechnen.

von Matthias L. (Gast)


Lesenswert?

1
uint16_t fNormierung ( uint16_t DivRest )
2
{
3
  uint32_t  u32Temp = DivRest;
4
  //--------------------------
5
  u32Temp *= 1000;
6
  u32Temp += 32768;
7
  //--------------------------
8
  return (uint16_t) (u32Temp>>16);
9
}

Das macht dir aus 0..65535 ein 0..999

von Thomas (Gast)


Lesenswert?

Wenn es extrem schnell gehen soll, auf 0-255 normieren (d.h. nur die 
oberen 8 Bit nehmen) und über eine Tabelle mit 256 Bytes im Flash auf 
0-99 um-"rechnen".

Ansonsten die Rechenoperation Obere_8_Bit / 255 * 99 so umformen, dass 
aus dem Multiplikator 99 / 255 etwas wird, bei dem der Nenner eine 
2er-Potenz ist, damit die Division zum Bitshift wird - z.B. Ergebnis 
=(Obere_8_Bit * 99L + 128) >> 8. Der Term "+ 128" dient der Rundung (ich 
gehe davon aus, dass alles unsigned ist, deshalb +) und >>8 entspricht 
einer Division durch 256, was nahe genug an 255 ist.

Die Multioplikation ist dann der einzige rechenintensive Teil - und 
ATmegas haben eine schnelle Hardware-Multlikation. Zwar nur 8bit, aber 
die verwendet der Compiler auch für 8bit x 16bit.

von hyggelig (Gast)


Lesenswert?

> /255 * 99
nein.

Wenn dann /256 * 100 + halbes Bit.
Genau so, wie es Matthias gezeigt hat wird's richtig !

von Thomas (Gast)


Lesenswert?

> Wenn dann /256 * 100 + halbes Bit

Quark. Mit (x * 100 + 128) / 256 wird aus 255 nicht wie gewünscht 99 
sondern 100. Also nähert man sich dem richtigen Faktor mit (x * 99 + 
128) / 256 und nicht mit (x * 100 + 128) / 256. Mathematisch ist das ein 
Fehler beim Multiplikator von 1,00xx vs. 0.99xx.

von Matthias L. (Gast)


Lesenswert?

Dann lässt man eben die Rundung weg.

von hyggelig (Gast)


Lesenswert?

das halbe Bit macht draus ein kaufmännisches Runden.

Trotzdem. Auch ohne dieses ist:
/256 * 100
richtig und nicht *99

von Thomas (Gast)


Lesenswert?

> Auch ohne dieses ist: /256 * 100 richtig und nicht *99

Jetzt wird es aber albern. Ob man sich dem mathematisch korrekten Faktor 
von oben unten nähert, ist mathematisch egal. Es ist idiotisch zu 
behaupten, dass eine Lösung "falsch" ist. Wenn man sich dem Faktor von 
oben nähert, muss man allerdings damit rechnen, dass das Ergebnis den 
vorgesehenen Wertebereich verlässt.

von hyggelig (Gast)


Lesenswert?

> Auch ohne dieses ist: /256 * 100 richtig und nicht *99
Ich korrigiere mich:
Bei Integer Arithmetik natürlich *100/65536. Zuerst multiplizieren, dann 
dividieren. Dadurch verlässt man kurz den 16Bit Wertebereich.

Oder eben höchstes Byte *100 /256, wie Du es gesagt hast. Ist nicht ganz 
das gleiche, aber ähnlich.

... ja .. eigentlich genau, wie es Matthias als Code-Beispiel zeigt. 
Über das halbe Bit kann man noch diskutieren.

von hyggelig (Gast)


Lesenswert?

Man kann auf im 16 Bit Wertebereich bleiben, muss dann aber die Rechnung 
in mehreren kleineren Schritten durchführen, da man sonst Genauigkeit 
verlieren würde (vor allem bei 0..999):

0 .. 65535 auf 0..99:
y = x /8 * 5 / 8 * 5 / 256;

0 .. 65535 auf 0..999:
y = x /8 * 5 / 8 * 5 / 8 * 5 / 16;

von Weingut P. (weinbauer)


Lesenswert?

/256 kann man sich auch schenken, einfach nur das Highbyte verwenden

von hyggelig (Gast)


Lesenswert?

nein. Dann verliert man an Genauigkeit.

von hyggelig (Gast)


Lesenswert?

stimmt ... hatte ich falsch verstanden.

von Thomas (Gast)


Lesenswert?

> /256 kann man sich auch schenken, einfach nur das Highbyte verwenden

Ich hoffe doch sehr, dass der gcc-Optimizer solche Sachen wie >>8, /256 
u.ä. automatisch ideal löst, so dass man es hübsch hinschreiben kann.

von hyggelig (Gast)


Lesenswert?

Beim Cosmic Compiler weiss ich, dass er aus

y= x / 256; ein

y = MSB(x);
macht

Ich hab sogar mal gesehen, dass er aus einem
y = x / 128;

ein:

y = MSB(x << 1);

macht, da 7x Schieben zu lange dauert.

Wobei es auch ähnlich sein kann, denn das höherwertigste Bit darf ja 
nicht verloren gehen.

von W.S. (Gast)


Lesenswert?

dieter kuhn schrieb:
> Also für 0 will ich 0 erhalten.
> Und für 65535 möchte ich 100 oder 1000 bzw. noch besser 99 oder 999
> erhalten.

Pack das Ganze in den low-Teil eines 32 Bit Registers, nimm mal 100 bzw. 
1000 und verwende dann den high-Teil des 32 Bit Registers

var
  DW : DWORD;

begin
  DW:= DerRest;
  DW:= DW * 100;  // oder eben 1000
  result:= HiWord(DW);
end;



W.S.

von Sascha W. (sascha-w)


Lesenswert?

dieter kuhn schrieb:
> Hallo zusammen.
>
> Ich habe einen 16Bit Nachkommawert von einer 16Bit Division.
bei einer 16Bit-Integer-Division? -> also den REST

> Ich möchte
> den Nachkommawert gern auf 100 oder 1000 normieren.
ok

> Also für 0 will ich 0 erhalten.
> Und für 65535 möchte ich 100 oder 1000 bzw. noch besser 99 oder 999
> erhalten.
das ist schon mal Quatsch, denn der Rest kann nie größer sein als der 
bei der Division verwendete Divisor. Damit ändert sich der auf 100 o. 
1000 zu normierende Bereich abhängig vom Divisor.
den normierten Wert berechnest du mit:

REST * 1000 / Divisor  oder REST * 100 / Divisor

Sascha

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.