Guten Morgen,
ich möchte im Mikrocontroller in der Programmiersprache Ansi C einen
Filter implementieren. Eine Fließkommazahl wird dabei mit einem double-
Wert multipliziert.
1
1/20*data[i]....
(data ist ein Array vom Typ double)
Wie kann man den Faktor 1/20=0.05 optimiert mit Schiebeoperatoren in
Ansi C implementieren?
Für jeden Vorschlag bin ich sehr dankbar.
Bye
Ich bin mir jetzt nicht sicher.
Aber es könnte sein, dass 1/20 als integer berechnet wird, was dann 0
ergibt.
Es könnte sein, dass man besser 1.0/20 schreiben sollte.
Kannst Du nicht auf Festkommarechnungen umsteigen?
Also statt 0.05 den Wert 5 verwenden und Data (also integer) mit 100
multiplizieren?
Nur so 'ne idee.
Vielen Dank für die schnellen Antworten.
Nach eurer Erfahrung kann man die nicht weiter optimieren?
Hab gedacht man kann dies mit Schiebeoperatoren wesentlich optimieren.
Hatte da mal ein perl-script geschrieben, was sowas berechnet
Das spuck fü .0.2 folgende Liste aus:
die abweichung vom 0.02 nimmt immer weiter ab.
( x * 1 ) >> 5 = x * 0.03125
( x * 1 ) >> 6 = x * 0.015625
( x * 3 ) >> 7 = x * 0.0234375
( x * 5 ) >> 8 = x * 0.01953125
( x * 11 ) >> 9 = x * 0.021484375
( x * 21 ) >> 10 = x * 0.0205078125
( x * 41 ) >> 11 = x * 0.02001953125
( x * 81 ) >> 12 = x * 0.019775390625
( x * 163 ) >> 13 = x * 0.0198974609375
( x * 327 ) >> 14 = x * 0.01995849609375
( x * 655 ) >> 15 = x * 0.019989013671875
( x * 1311 ) >> 16 = x * 0.0200042724609375
( x * 2621 ) >> 17 = x * 0.0199966430664063
( x * 5243 ) >> 18 = x * 0.0200004577636719
( x * 10485 ) >> 19 = x * 0.0199985504150391
( x * 20971 ) >> 20 = x * 0.0199995040893555
( x * 41943 ) >> 21 = x * 0.0199999809265137
( x * 83887 ) >> 22 = x * 0.0200002193450928
( x * 167773 ) >> 23 = x * 0.0200001001358032
( x * 335545 ) >> 24 = x * 0.0200000405311584
( x * 671089 ) >> 25 = x * 0.0200000107288361
( x * 1342177 ) >> 26 = x * 0.0199999958276749
( x * 2684355 ) >> 27 = x * 0.0200000032782555
( x * 5368709 ) >> 28 = x * 0.0199999995529652
( x * 10737419 ) >> 29 = x * 0.0200000014156103
( x * 21474837 ) >> 30 = x * 0.0200000004842877
( x * 42949673 ) >> 31 = x * 0.0200000000186265
du musst natürlich auf deinen Wertebereich achten, damit bei der
Multiplikation das x nicht überläuft.
optimieren kannst du das nur, wenn du die doubles wegbekommst und durch
fix-points ersetzt.
oder mach wenigstesn floats aus den doubles (wenn das auf deinem System
nicht sowiso identisch ist)
Was hast du denn für einen µC? Wenn der eine FPU hat brauchst du dir
natürlich gar keine gedanken machen, dann fürd ich nur auf
>Kannst Du nicht auf Festkommarechnungen umsteigen?>Also statt 0.05 den Wert 5 verwenden und Data (also integer) mit 100>multiplizieren?
Naja ein skalierungsfaktor von 100 ist auch nicht wirklich ideal.
besser wär eine Potenz von 2
wenn du zwei werte mit skalierungsfaktor 100 multiplizierstz ist die
resultierende skalierung 200, das heißt du musst durch 10000, dh du
musst durch 100 teilen, wenn du die ureprüngliche wieder haben willst.
wenn du mit zB 128 skalierst, musst du nach der multiplikation durch 128
teilen, was nur ein bitshift ist
>wenn du zwei werte mit skalierungsfaktor 100 multiplizierstz ist die>resultierende skalierung 200, das heißt du musst durch 10000, dh du>musst durch 100 teilen, wenn du die ureprüngliche wieder haben willst.
quatsch, da ist ein satzteil zu viel:
so sollte es aussehen:
>wenn du zwei werte mit skalierungsfaktor 100 multiplizierstz ist die>resultierende skalierung 10000, dh du musst durch 100 teilen, wenn du die
ureprüngliche wieder haben willst.
new_gast schrieb:
> Vielen Dank für eure zahlreichen Beiträge. Bin jetzt irgendwie verwirrt.> Was soll ich nun tun?
Zuerst mal darüber nachdenken, wie du aus data einen int oder long
machen kannst. Solange data double ist, ist es sinnlos über die Division
von 1/20.0 nachzudenken.
Vorgehensweise:
Den möglichen Wertebereich festlegen und auch welche Operationen mit
diesen Werten gemacht werden. Mit diesem Wissen kann man dann hergehen
und Skalierfaktoren festlegen um die kompletten Berechnungen von double
in den Ganzzahlbereich zu verlagern.
Da wir nicht wissen, um welchen µC es sich handelt, tippe ich darauf,
daß die double-Variable intern vom Compiler als float behandelt wird.
Zweitens sehe ich garkeine Notwendigkeit, irgendeine Optimierung
durchzuführen. Probleme bei der Verarbeitungsgeschwindigkeit sind nicht
erwähnt.
Soll der Compiler doch optimieren, wo er kann.
Zumindest macht jeder halbwegs intelligente Compiler aus
1.0/20*x ein 0.05*x; notfalls kann man es von Hand so
hinschreiben.
Damit hat man schon mal keine Division, sondern eine
Multiplikation.
Vielleicht kann man das Programm auch so umbauen, daß es
nicht gerade 20 sein muß?
Wenn es nur eine Skalierung ist, die etwas in die richtige
Größenordnung schiebt und man auch z.B. mit 16 oder 32 leben
kann, kann man 1/16.0*x oder 1/32.0*x auch durch ein einfaches
Shiften direkt im Exponentialteil der Gleitkommazahl
ersetzen.
>Zweitens sehe ich garkeine Notwendigkeit, irgendeine Optimierung>durchzuführen. Probleme bei der Verarbeitungsgeschwindigkeit sind nicht>erwähnt.
Wenn er so ne kleine division mit ner Konstante wegbekommen will, gehe
ich mal davon aus, dass er Laufzeitprobleme hat.
Eine eigene Frage?
Dieser Thread ist über 17 Jahre alt.
Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.