ENGLISH VERSION |
|
Links | | | Forum | | | Kommentare | | | News melden |
Chat | | | Umfragen | | | Newsticker | | | Archiv |
amiga-news.de Forum > Programmierung > Log Lookup Table | [ - Suche - Neue Beiträge - Registrieren - Login - ] |
-1- | [ - Beitrag schreiben - ] |
03.09.2004, 11:17 Uhr bubblebobble Posts: 707 Nutzer |
Hallo! Ich möchte einen LookUp Table machen für log(n), wobei n eine float zwischen 0 und 100.000.000 ist. Problem ist nun, dass ich eine LookUp Table Größe von ca 10.000 Einträgen machen will. Dadurch würde aber der Wertebreich bei kleinen Zahlen sehr grob und bei großen Zahlen unnötig fein aufgelöst. Weiss jemand wie man das optimieren kann ? Ich könnte noch linear interpolieren zwischen den Einträgen, was das prinzipielle Problem aber nicht behebt. -- Thilo Köhler, Author von: HD-Rec, Samplemanager, ArTKanoid, Monkeyscript, Toadies, AsteroidsTR, TuiTED, PosTED, UDM, TKPlayer, TKUnpacker Homepage: http://www.hd-rec.de [ - Antworten - Zitieren - Direktlink - ] |
03.09.2004, 13:13 Uhr Solar Posts: 3680 Nutzer |
Hmm... ich weiß nicht, aber bei floats bietet sich eine Lookup-Tabelle nicht wirklich an, oder? Was spricht gegen die Standardfunktion log()? [ - Antworten - Zitieren - Direktlink - ] |
03.09.2004, 13:20 Uhr Mad_Dog Posts: 1944 Nutzer |
Zitat: Wenn Du float oder double nimmst, werden die Zahlen im IEEE 754 Format im Speicher abgelegt. Da gibt's keinen Unterschied bezüglich der Genauigkeit bei kleinen oder großen Zahlen. Der Wertebereich für IEEE 754 32 Bit bzw. 64 Bit ist konstant. -- http://www.norman-interactive.com [ Dieser Beitrag wurde von Mad_Dog am 03.09.2004 editiert. ] [ - Antworten - Zitieren - Direktlink - ] |
03.09.2004, 13:25 Uhr Holger Posts: 8116 Nutzer |
Zitat:Ja, berechne einfach den Logarithmus und lasse den Lookup und das Interpolieren weg. Damit sparst Du zwei Speicherzugriffe und mehrere Rechenoperationen. mfg -- Good coders do not comment. What was hard to write should be hard to read too. [ - Antworten - Zitieren - Direktlink - ] |
03.09.2004, 14:12 Uhr bubblebobble Posts: 707 Nutzer |
Also vielleicht hab ich mich nicht klar ausgedrückt: Ich weiss wie Floats aufgebaut sind. Die Flaots bewegen sich zwischen 0 und 100.000.000. Ich soll den logarithmus draus ziehen. Der *Wertebereich* (NICHT der Definitionsbereich) sind bei einem normalen Lookup Table schlecht aufgelösst wenn es sich um log handelt. (ihr wiss ja wie eine Log Kurve aussieht. am Anfang steigts noch, später immer langsamer). log (1) = 0 log (10) = 1 log (100) = 2 log (1.000) = 3 log ( 90.000.000) = 7,95 log (100.000.000) = 8 Wenn mein Table 1000 Einteäge besitzt, dann muss ich 100.000er Schritte im Table machen, dadurch ist der Wertebereich von 0-4 total futsch, dafür von 4-8 sehr hoch aufgelösst. Ich will einen Table machen, weil das ganze auf einem PDA ohne FPU laufen soll. Ich habs mal getestet, ein Table ist dort ca. 20mal so schnell wie ein log(n). -- Thilo Köhler, Author von: HD-Rec, Samplemanager, ArTKanoid, Monkeyscript, Toadies, AsteroidsTR, TuiTED, PosTED, UDM, TKPlayer, TKUnpacker Homepage: http://www.hd-rec.de [ - Antworten - Zitieren - Direktlink - ] |
03.09.2004, 14:33 Uhr thomas Posts: 7718 Nutzer |
Also, ich habe verstanden, du möchtest sowas haben: double log10 (unsigned long n) { return (logtable[n]); } wobei sich n zwischen 0 und 100.000.000 bewegt und die logtable den entsprechenden Logarithmus zur Basis 10 enthält. Nur sind dir 800MB Tabelle zu viel. Wie wär's mit sowas: double log10 (unsigned long n) { if (n < 1000) return (logtab1[n]); if (n < 1000000) return (logtab2[n/1000]); /* 1000000 <= n <= 100000000 */ return (logtab3[n/1000000]); } (ist nur ein Beispiel, ob das mathematisch sinnvoll ist, darüber habe ich nicht nachgedacht). Gruß Thomas -- Email: thomas-rapp@web.de Home: home.t-online.de/home/thomas-rapp/ [ - Antworten - Zitieren - Direktlink - ] |
03.09.2004, 14:47 Uhr bubblebobble Posts: 707 Nutzer |
Einer der mich versteht ;-) Ja, genau daran hatte ich auch schon gedacht. Ist besser als nix, ich hoffe die If's machen mir die Performance nicht wieder kaputt. Aber auf sowas wirds wohl rauslaufen. Danke für den Tip. -- Thilo Köhler, Author von: HD-Rec, Samplemanager, ArTKanoid, Monkeyscript, Toadies, AsteroidsTR, TuiTED, PosTED, UDM, TKPlayer, TKUnpacker Homepage: http://www.hd-rec.de [ - Antworten - Zitieren - Direktlink - ] |
03.09.2004, 16:12 Uhr Holger Posts: 8116 Nutzer |
Ich kann Dir nur das hier anbieten:code:Für andere Logarithmen mußt Du ja nur den Faktor anpassen.inline float FastLog10(float p_X) { // Retrieve a coarse log value from the exponent of the encoded float int* const intX = reinterpret_cast<int*>(&p_X); const int coarseLog2 = ((*intX >> 23) & 0xFF) - 127; // Set the exponent to 1 *intX &= 0x007FFFFF; *intX |= 0x3F800000; // Improve the coarse log value using a quadratic approximation // of log over the range [1, 2] static const float A = -(1.0f / 3.0f); static const float B = 2.0f; static const float C = -(5.0f / 3.0f); p_X = (((A * p_X) + B) * p_X) + C + static_cast<float>(coarseLog2); // Convert log to base 10 and return static const float LogBase10of2 = 0.30102999566398119521373889472449f; return (p_X * LogBase10of2); return p_X; } mfg -- Good coders do not comment. What was hard to write should be hard to read too. [ - Antworten - Zitieren - Direktlink - ] |
03.09.2004, 20:24 Uhr bubblebobble Posts: 707 Nutzer |
Zitat: Das ist genial, aber läuft leider nicht unter eMbedded VisualC++. Er meckert schon, dass nach "inline" kein "(" käme. komisch. Ich habe es dann direkt eingebaut, weil ich es nur einmal brauche. Aber dann hat er bei "reinterpret_cast" gemeckert. Kann das jemand etwas umschreiben, dass es einfacher für den Compiler ist ? Aber man könnte folgendes draus machen: Ich lese den Exponenten aus der Float raus, das geht ja schnell. Und daraufhin entscheide ich den Lookup Table, und mache 8 Tables (wenn der höchste exponent 8 ist). Danke für die Tips soweit. -- Thilo Köhler, Author von: HD-Rec, Samplemanager, ArTKanoid, Monkeyscript, Toadies, AsteroidsTR, TuiTED, PosTED, UDM, TKPlayer, TKUnpacker Homepage: http://www.hd-rec.de [ - Antworten - Zitieren - Direktlink - ] |
03.09.2004, 21:03 Uhr bubblebobble Posts: 707 Nutzer |
@Holger: Weist du wie ich A, B und C anpassen muss, wenn der log zwischen [1,100.000.000] liegt und nicht zwischen [1, 2] ? Ansonsten hab ich das nun am Laufen, evtl. ist es nicht ganz optimal weil ich diese Super-tricks wie "reinterpret" etc. weggelassen habe, aber es ist immerhin noch 6mal so schnell wie ein echter log10(). Jetzt werde ich evtl. statt der Verfeinerung mit A, B und C mehrere Lookup Tables machen. -- Thilo Köhler, Author von: HD-Rec, Samplemanager, ArTKanoid, Monkeyscript, Toadies, AsteroidsTR, TuiTED, PosTED, UDM, TKPlayer, TKUnpacker Homepage: http://www.hd-rec.de [ - Antworten - Zitieren - Direktlink - ] |
05.09.2004, 13:13 Uhr Holger Posts: 8116 Nutzer |
Zitat:Überhaupt nicht. Du hast den Algorithmus nicht verstanden. float Zahlen liegen in der Form m * 2 ^ n vor, wobei m zwischen 1 und 2 liegt. Deshalb ist der logarithmus zur Basis 2 n + ln2 m Und es muß nur der Logarithmus für Werte zwischen 1 und 2 approximiert werden, da Mantisse und Exponent aus der float-Zahl mittels einfache integer-Bitoperationen extrahiert werden kann. Zitat:reinterpret_cast ist genau das, was ein herkömmlicher pointer-cast unter C auch macht, nur daß man damit auch deklariert, daß genau dieses Verhalten gewollt ist. mfg -- Good coders do not comment. What was hard to write should be hard to read too. [ - Antworten - Zitieren - Direktlink - ] |
05.09.2004, 13:41 Uhr bubblebobble Posts: 707 Nutzer |
Zitat:Ja, habs dann auch gesehen. Vielen Dank nochmal für diesen Algorithmus, funktioniert prächtig. Ich hab noch eine Version gemacht, die nur den Exponenten nimmt, das ist 100mal schneller als log10 auf dem PDA. Das reicht teilweise sogar von der Genauigkeit her, da mein Zahlenbereich ja recht gross ist. Gibt es irgendeine Quelle woher dieser Algorithmus stammt ? Ist zwar mehr oder weniger Mathematik, aber ich muss ja sicher gehen, da ich es in einer Diplomarbeit verwende. Vor allem eine Quelle für die Approximation wäre hilfreich. -- Thilo Köhler, Author von: HD-Rec, Samplemanager, ArTKanoid, Monkeyscript, Toadies, AsteroidsTR, TuiTED, PosTED, UDM, TKPlayer, TKUnpacker Homepage: http://www.hd-rec.de [ - Antworten - Zitieren - Direktlink - ] |
13.09.2004, 18:16 Uhr Holger Posts: 8116 Nutzer |
Den Code habe ich auch nur aus einem Diskussionsforum zum Thema Audioprogrammierung. Aber wie Du selbst feststellst, ist alles bis auf die Approximation trivial. Für die in dem Code enthaltene Berechnung konnte ich keine Quelle finden, wenn Du eine rechtlich sichere benötigst, kann Du eine andere Approximation aus der Taylor Reihe herleiten. Diese Reihe ermöglicht Polynome beliebigen Grades, je höher, desto genauer. Für den 2. Grad gilt: ln(x)~=(x-1)-(x-1)²/2 Das kann man umstellen zu ½(2(x-1)-(x-1)²)=½(x-1)(2-(x-1)) =½(x-1)(3-x) Um vom natürlichen Logarithmus zur Basis 2 zu kommen, muß man noch durch ln(2) teilen, das kann man mit ½ zusammenfassen zu: (x-1)(3-x)*0.72134752044448 Ändere also im Code code:zustatic const float A = -(1.0f / 3.0f); static const float B = 2.0f; static const float C = -(5.0f / 3.0f); p_X = (((A * p_X) + B) * p_X) + C + static_cast<float>(coarseLog2); code:p_X = (p_X-1)*(3-p_X)*0.72134752044448 + static_cast<float>(coarseLog2); Dann hast Du einen nachvollziehbaren Algorithmus. mfg PS: Ich hoffen, es hat sich jetzt kein Fehler eingeschlichen... -- Good coders do not comment. What was hard to write should be hard to read too. [ Dieser Beitrag wurde von Holger am 13.09.2004 editiert. ] [ - Antworten - Zitieren - Direktlink - ] |
14.09.2004, 06:25 Uhr Solar Posts: 3680 Nutzer |
Wer es genauer haben will als eine grobe Annäherung, dem sei Cody & Waite empfohlen - "Software Manual for the Elementary Functions". Kostet eine ganze Stange Geld, bietet aber sehr gutes Material. [ - Antworten - Zitieren - Direktlink - ] |
14.09.2004, 10:49 Uhr bubblebobble Posts: 707 Nutzer |
@Holger Vielen Dank. Das war mir sehr hilfreich. (und lehrreich ) -- Thilo Köhler, Author von: HD-Rec, Samplemanager, ArTKanoid, Monkeyscript, Toadies, AsteroidsTR, TuiTED, PosTED, UDM, TKPlayer, TKUnpacker Homepage: http://www.hd-rec.de [ - Antworten - Zitieren - Direktlink - ] |
01.10.2004, 13:37 Uhr bubblebobble Posts: 707 Nutzer |
Zitat: Die Approximation mit dem Tylorpolynom für ln x habe ich nachvollzogen, das funktioniert auch. Aber in deinem Codebeispiel wird eine andere Aproximation gemacht, wie du siehst ergibt dich nicht das Polynom 1/2(x-1)(3-x) sondern 1/3(x-1)(5-x) hm... Wo kommt das denn her ? Die letztere Version ist 10mal genauer im Druchschnitt. Es wird auch nicht mit ln 2 Dividiert, deshalb müsste das so eine Art Taylor Polynom direkt für log10 sein. Ich kann das aber nicht herleiten. Evtl. ist das kein Taylor Polynom sondern was anderes, was nur so ähnlich aussieht ? -- Thilo Köhler, Author von: HD-Rec, Samplemanager, ArTKanoid, Monkeyscript, Toadies, AsteroidsTR, TuiTED, PosTED, UDM, TKPlayer, TKUnpacker Homepage: http://www.hd-rec.de [ - Antworten - Zitieren - Direktlink - ] |
01.10.2004, 16:08 Uhr bubblebobble Posts: 707 Nutzer |
@Holger: ln(x) ~= 1/2(x-1)(3-x) scheint eine Approximation für ln(x) zu sein, wärend ld(x) ~= 1/3(x-1)(5-x) (?) wohl eine Appromixation für ld(x) ist. (Logatihmus Dualis, also zur Basis 2). Kannst du das bestätigen ? Die zweite Variante ist dabei wesentlich genauer, ca. um den Faktor 10. Ich kann leider kein Taylor Polynom finden oder herleiten was auf das herauskommt. -- Thilo Köhler, Author von: HD-Rec, Samplemanager, ArTKanoid, Monkeyscript, Toadies, AsteroidsTR, TuiTED, PosTED, UDM, TKPlayer, TKUnpacker Homepage: http://www.hd-rec.de [ - Antworten - Zitieren - Direktlink - ] |
02.10.2004, 17:27 Uhr Holger Posts: 8116 Nutzer |
Zitat:Natürlich, deshalb mußt Du ja bei der oberen Variante durch ln(2) teilen, bei der unteren nicht. Zitat:Konnte ich nicht beobachten. Die Genauigkeit hing hauptsächlich von der Genauigkeit der Konstante ab. Bei den meisten Prozessoren spielt es für die Performance keine Rolle, ob die Zwischenrechnungen in float oder double stattfinden, deshalb kann man dafür double verwenden. Zitat:Deshalb habe ich ja auch die Taylor-Variante angeboten, weil ich nicht weiß, wie die erste Variante hergeleitet wurde. mfg -- Good coders do not comment. What was hard to write should be hard to read too. [ - Antworten - Zitieren - Direktlink - ] |
02.10.2004, 21:52 Uhr bubblebobble Posts: 707 Nutzer |
Naja, die Genauigkeit hängt eigentlich viel mehr von der Approximations Formel ab. Beispiel: ln(x) ~= 1/2(x-1)(3-x) , x aus (0,2] Dann wäre ln(2) ~= 1/2 * 1 * 1 = 0.5 Tatsächlich ist aber ln(2) = 0.693... ABER nach dieser Formel: ld(x) ~= 1/3(x-1)(5-x) ld(2) ~= 1/3 * 1 * 3 = 1 ld(2) = 1 Da ist es wurscht ob ich mit Float oder Double rechne. Ich hab das über ein paar Tausend Testdaten laufen lassen, und die Approximation des Log Dualis war 10 mal genauer, also eine Dezimalstelle besser. Deshalb würde ich gerne diese Formel benutzen, aber da es eine Diplomarbeit ist muss ich das natürlich irgendwie fundieren können. Schade dass du nicht mehr weisst woher das ist. Ein Taylor Polynom scheint es nicht zu sein, jedenfalls kann ich es nicht herleiten. Trotzdem vielen Dank für deine Hilfe! -- Thilo Köhler, Author von: HD-Rec, Samplemanager, ArTKanoid, Monkeyscript, Toadies, AsteroidsTR, TuiTED, PosTED, UDM, TKPlayer, TKUnpacker Homepage: http://www.hd-rec.de [ - Antworten - Zitieren - Direktlink - ] |
03.10.2004, 13:07 Uhr Holger Posts: 8116 Nutzer |
Zitat:Wieso betrachtest Du für die Analyse der Genauigkeit des Algorithmus nicht auch den den Algorithmus, den Du verwendest? Der verwendete Algorithmus zerlegt nunmal die IEEE-FP Zahl, bevor Du approximierst, und dann ist es vollkommen uninteressant, wie ungenau die Formel für den Wert 2 ist, da die Matisse _immer_ in [1, 2[ liegt, das heißt für die Zahl 2 ist die Mantisse 1. Da ln(1) = 0 und beide Formeln EXAKT auf dieses Ergebnis kommen, bleibt nur der Exponent aus Deiner Floating-Point Zahl übrig, EXAKT 1. Zitat:Das sehe ich da oben irgendwie nicht, Du vergleichst einen natürlichen Logarithmus mit einem zur Basis zwei für eine in Bezug auf den eigentlichen Algorithmus irrelevanten Zahl. Wie Du den Begriff Genauigkeit definierst, will ich da schon gar nicht wissen. Eine solche Genauigkeitsbetrachtung ist vollkommener Unsinn, wenn Du bereits im vorhinein eine nichtzutreffende Annahme zur Grundlage machst. Es ist vollkommen egal, wie genau ein Teil ist, Du willst schließlich das Endergebnis haben, das war log10, und das war bei meinen Testreihen stellenweise sogar _genauer_ als die andere Variante. Abgesehen davon, hast Du von Zahlenbereichen gesprochen, bei denen der Exponent so hoch ist, daß Du sogar mit dem Gedanken gespielt hast, die Approximation ganz wegzulassen. Da frage ich mich schon, wieso Du Dich jetzt an so minimale Abweichungen stößt. Schließlich ist die max. Abweichung von ca. 0.2 _absolut_, das heißt unabhängig von der Größenordnung des Endergebnisses. mfg -- Good coders do not comment. What was hard to write should be hard to read too. [ - Antworten - Zitieren - Direktlink - ] |
23.11.2004, 11:37 Uhr bubblebobble Posts: 707 Nutzer |
Also die Approximation mit ln x =~ 1/2(x-1)(3-x) ist ein Taylorpolynom, das ist einfach. ld x =~ 1/3(x-1)(5-x) ist vermutlich KEIN Taylorpolynom. Es könnte evtl. ein Chebysev Polynom sein. Kennst sich da jemand aus und kann das bestätigen oder sogar herleiten ? Das wäre mir eine riesen Hilfe! -- Thilo Köhler, Author von: HD-Rec, Samplemanager, ArTKanoid, Monkeyscript, Toadies, AsteroidsTR, TuiTED, PosTED, UDM, TKPlayer, TKUnpacker Homepage: http://www.hd-rec.de [ - Antworten - Zitieren - Direktlink - ] |
-1- | [ - Beitrag schreiben - ] |
amiga-news.de Forum > Programmierung > Log Lookup Table | [ - Suche - Neue Beiträge - Registrieren - Login - ] |
Impressum |
Datenschutzerklärung |
Netiquette |
Werbung |
Kontakt
Copyright © 1998-2024 by amiga-news.de - alle Rechte vorbehalten. |