Ich suche einen AVR-tauglichen (Festkomma-)Algorithmus, der den Logarithmus einer 32-Bit Zahl bildet. Zu welcher Basis ist egal, das ist ja nur ein Faktor im Ergebnis. Vermutlich ist die Basis 2 am geeignetsten für Bitschiebereien. Meine Eingangswerte liegen im Bereich von ca. 1000 bis 100.000.000. Es muß nicht so fürchterlich genau sein, aber nur das höchste gesetzte Bit auszählen reicht mir nicht. Hat da jemand vielleicht was Nettes parat? Vielen Dank!
Gast
#704892
Potenzreihenentwicklung. Frage Wikipedia.
Gast
#704901
Der Logarithmus ist relativ einfach. Es beginnt damit zu zaehlen auf welcher Position das MSB ist. Fuer die folgenden bits nimmt man ein Tabelle. Eine Potenzreihe ist unpassend.
Gast
#704910
Gast
#705045
> Es muß nicht so fürchterlich genau sein, aber nur das höchste gesetzte > Bit auszählen reicht mir nicht. Ein genaueres Resultat kann man aber mit Festkomma-Zahlen gar nicht speichern. Das höchste Bit zu suchen ist also der einfachste, schnellste und genaueste Algorithmus der möglich ist mit Fix-Point-Arithmetik. Beweisskizze: x sei ein unsigned 32-bit Integer (ganz normal, kein Komma). Der Wertebereich liegt zwischen 0 und 2^32-1. log2(x) wird sich entsprechend zwischen -unendlich und 32 bewegen. Soll der log2 wiederum in dem selben Datentyp abgelegt werden, muss man auf ganze Zahlen runden (z.B. hier z.B. abrunden). Somit sind nur 32 Werte als Resultat möglich. Wenn du die wieder zurück-exponenzierst wirst du feststellen das dies genau jene 32 Fälle sind, die du per MSB Bit-Zählen bekommst. Nun zur Fix-Point-Arithmetik. Sei b=Komma-Position dann kann man eine 32-bit-Fix-Punkt Zahl y Schreiben als y = x / 2^b. Wobei x ein 32-bit-Int ist. Es folgt: log2(y) = log2(x / 2^b) = log2(x) - log2(2^b) = log2(x) - b. Sprich der fix-point-log unterscheidet sich nur duch eine ganzzahlige Subtraktion vom integer-log, eine höhere Genauigkeit ist also nicht möglich. Wenn dir die Genauigkeit nicht ausreicht, müssen input und output Datentyp des Logarithmus eine unterschiedliche Komma-Position haben.
Gast
#705055
Hmm Moment, irgenwas stimmt da doch ganz und gar nicht. Ich glaub was ich da geschrieben hab ist falsch, zumindest der fix-point Teil. Ich schau mir das Morgen nochmals an (brauch wohl etwas Schlaf) :-)
Gast
#705080
@Stefan: Endlich mal einer, der seine Aussagen ordentlich begründet. Aber ich glaube, in dem Beweis steckt ein kleiner Fehler: > log2(y) = log2(x / 2^b) = log2(x) - log2(2^b) = log2(x) - b = (log2(x) - b) * 2^b / 2^b (log2(x) - b) * 2^b (gerundet) ist also der Wert, der als Ergebnis in die 32-Bit-Variable geschrieben wird und repräsentiert eine Zahl mit b Nachkommastellen. Anders als in deiner ersten Beweishälfte ist log2(x) jetzt natürlich keine Ganzzahl mehr. Folglich ist es kein Problem, aus einer Festkommazahl mit b Nachkomma- stellen den Logarithmus mit ebenfalls b Nachkommastellen zu berechnen. Oder denke ich da falsch? > Wenn dir die Genauigkeit nicht ausreicht, müssen input und output > Datentyp des Logarithmus eine unterschiedliche Komma-Position haben. Was sicher auch kein Problem wäre. Mein Favorit wäre übrigens der erste Vorschlag von sechseinssechs (Schieben und Tabelle).
Ich habe mich an den Vorschlag Schieben+Tabelle gehalten. Per Tabelle nähere ich aus 16 Geradenstücken an. Meine Annäherung liegt wegen der Krümmung unter der Originalkurve, für kleineren durchschnittlichen Fehler könnte man die etwas höher schieben, ich weiß aber nicht wie man diesen Ausgleich berechnen täte. Die Genauigkeit ist schon bemerkenswert hoch, nahe 10e-5. Hier ist mein erster Code:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | |
26 | |
Die Hi/Lo Teile kann man mit Unions wohl noch optimieren.
Gast
#705282
Merci yalu Genau da lag mein Fehler. Offensichtlich kann man mit Fix-Point Arithmetik den Logarithmus genauer darstellen. Das ist mir beim erneuten durchlesen dann auch aufgefallen, nur um mit dem Finger darauf zu zeigen war ich dann doch zu müde. Sorry wenn ich für Verwirrung gesorgt habe :) Schliesse mich 616 an. Die Zahl ins 1..2 Intervall schieben und dann eine der üblichen Approximationsmethoden verwenden. Der Logartihmus ist in dem Bereich ja ziemlich "zahm". Für eine erste grobe Approximation könnte man einfach den Wert übernehmen (Approx durch Gerade mit Steigung 1).
Mit Unions zum partiellen Zugriff auf die Teile eines 32-bit Wertes kriege ich es effizenter, im Hinblick auf 8 Bit Controller ohne Barrel-Shifter. Außer der MSB-Suche sind keine Shifts mehr nötig, wenn ich damit passend für eine Bytegrenze aufhöre. Mit diesem Code kann ich die oberen 3 Bit des Eingangswertes nicht nutzen, aber so große Werte treten bei mir nicht auf. (Bei Verdopplung der Tabellengröße würde man ein Bit davon zurückgewinnen)
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | |
26 | |
27 | |
28 | |
29 | |
30 | |
31 | |
32 | |
33 | |
34 | |
35 | |
36 | |
37 | |
38 | |
39 | |
40 | |
41 | |
42 | |
43 | |
44 | |
45 | |
46 | |
47 | |
48 | |
49 | |
50 | |
51 | |
52 | |
53 | |
54 | |
55 | |
56 | |
57 | |
Antwort schreiben
Bitte melde dich an, um einen Beitrag zu schreiben.