Datum: 02.12.2007 02:37
Hi, anbei findet Ihr einige Routinen, die das Rechnen mit 64 Bit float Zahlen auch auf den AVRs erlauben. Der Emulator ist in K&R C geschrieben und angepaßt und getestet für den Einsatz mit gcc. Er erlaubt die Rechnung mit ca. 15 gültigen Stellen anstelle der 6 Stellen für den eingebauten 32Bit float Typ. Das Zahlenformat entspricht IEEE754. Das Headerfile erzeugt einen neuen Typ float64_t , der in einem uint64_t untergebracht wird. 64Bit floats können von den vorhandenen standardisierten 32Bit floats konvertiert werden: (float64_t) x = f_sd((float32_t)a); (sd: single to double). Umgekehrt gehts so: (float32_t) x = f_ds((float64_t)a); Es sind die vier Grundrechenarten und die Kehrwertberechnung implementiert. (float64_t) x = f_add ((float64_t) a,(float64_t) b); (float64_t) x = f_sub ((float64_t) a,(float64_t) b); (float64_t) x = f_mul ((float64_t) a,(float64_t) b); (float64_t) x = f_div ((float64_t) a,(float64_t) b); (float64_t) x = f_inverse((float64_t) a); Die Leistung für die Division liegt bei ca. 200 flops auf nem Mega 128 @16Mhz, Kehrwertbildung ist ähnlich lahm, der Rest geht schneller. Die Behandlung von Sonderzahlen (NaN, +/-Infinity, etc.) und Over/Underflows ist nicht normgerecht implementiert. 1/0 liefert allerdings Infinity und die Rundung zu 0 für betragsmäßig zu kleine Ergebnisse ist drin. Das File avr_f64.c enthält den Rechencode. Im main.c findet sich ein framework für den Test. Ich habe diese Routinen erstellt, weil ich für meine Belange mit dem 32 Bit Floatformat nicht genügend Genauigkeit erreichen konnte. Ich habe relativ viel Aufwand in die Tests gesteckt, wie auch im main.c zu sehen ist. Trotzdem kann ich natürlich Fehler nicht ausschließen. Ich würde mich über rege Benutzung und Rückmeldung freuen. Cheers Detlef
Datum: 09.04.2008 20:12
Gute Arbeit und kompakter Code ! Ich habe deinen Code zum Anlass genommen, die Bibliothek um die Funktionen sqrt, exp, log, sin, cos, tan, arcsin, arccos, arctan sowie um die Konvertierung vom und ins Dezimalsystem zu erweitern. Ich verwende dafür bestimmte Hilfsfunktionen, welche sich auch dazu eignen, die den Code für 4 Grundrechenarten kompakter zu schreiben. Daher habe ich +, -, *, / auch entsprechend abgeändert. Andernfalls würden Code-Teile, die Ähnliches tun, nebeneinander existieren, was man sich auf einem µC nicht leisten sollte. Meine Performance-Messungen auf einem ATMega32 (16 MHz) ergaben ca. 1000 Multiplikationen und 400 Divisionen pro Sekunde. Die Performance von exp, log, sin, cos, tan, arcsin, arccos, arctan hängt auch vom übergebenen Argument ab und lag zwischen 50 und 200 Funktionsauswertungen pro Sekunde. Der Code ist ebenfalls ANSI-C-kompatibel. Bei den math. Fkt. wird in den meisten Fällen die float64-Zahl geliefert, welche sich durch Rundung des exakten Ergebnisses ergibt. Manchmal wird in die falsche Richtung gerundet. Nur in speziellen Fällen kann es vorkommen, dass deutlich weniger als alle 52 Mantissebits signifikant sind: Wenn x nicht nahe bei Null, aber sehr nahe einer Nullstelle von sin, cos oder tan liegt, ist der absolute Fehler zwar in der Größenordnung 2E-16; weil der Funktionswert aber nahe bei Null liegt, ist der relative Fehler (= abs. Fehler / Fkt.-Wert) deutlich größer als 2E-16. Größere Fehler treten bei sin, cos, tan auch auf, wenn x betragsmäßig sehr groß ist, z.B. 1E10. Für die Praxis dürfte sich der Aufwand nicht lohnen, diese Fehler zu verkleinern. Ich habe den Code v.a. nach Compilierung unter Visual C++ und nur stichprobenartig auf dem eigentlichen Zielsystem (ATMega32) getestet. Die Funktionen sqrt, exp, log, sin, cos, tan, arcsin, arccos, arctan habe ich zum einen mit ausgewählten Spezial-Zahlen und zum anderen jeweils mit 1E9 Zufallszahlen getestet, bei denen sowohl Mantisse als auch Exponent zufällig waren. Das Ergebnis habe ich mit dem Ergebnis verglichen, das die double-Arithmetik unter VC++ liefert. Mögliche Differenzen wurden toleriert, wenn sich jeweils folgende beiden Intervalle überlappen: Das erste Intervall ergibt sich, indem der von meinem Code gelieferte Funktionswert einmal auf den nächstkleineren darstellbaren float64-Wert (untere Intervallgrenze) und zum anderen auf den nächstgrößeren (obere Grenze) abgeändert wird. Das zweite Intervall ergibt sich, indem die entsprechende Funktion der PC-math-Bib. mit dem nächstkleineren Funktionsargument und einmal mit dem nächstgrößeren Argument evaluiert wird. Bei den 1E9 zufälligen Funktionsargumenten waren alle Ergebnisse meines Codes mit diesen Kriterien tolerierbar. Das beweist jedoch nicht, dass es keinen Bug gibt. Bugs können gerade auch in Spezialfällen auftreten, die auch durch viele Tests mit Zufallszahlen nicht auftreten. Als Demo-Applikation benutze ich den mit einer RC5-Fernbedienung steuerbaren Taschenrechner, den ich auch schon für die Gleitkomma-Bibliothek Gleitkomma-Bibliothek für AVR verwendet habe. Man kann alle Funktionen der float64-Bibliothek mit #defines in der Datei avr_f64.h in die Kompilierung einbeziehen bzw. sie ausschließen. Wenn nur +, -, *, / sowie die Konvertierung vom und ins Dezimalsystem verwendet werden, benötigt die Taschenrechner-Applikation ca. 20 kB. Ich habe auf meinem ATMega32 noch exp und log aktiviert, was auf 28 kB führt. Mit allen Funktionen werden ca. 39 kB benötigt -- nichts für einen ATMega32. Außer der float64-Bibliothek verwende ich in der Taschenrechner-Anwendung den RC5-Code von Peter Dannegger, Code für LCDs von Peter Fleury und USART-Code von Ulrich Radig.
Datum: 09.04.2008 20:19
Ich habe in der Funktion f_to_string() einen Bug gefunden und korrigiert. Ich habe den alten Download gelöscht und den neuen Download eingestellt.
Datum: 13.04.2008 18:37
Ich habe festgestellt, dass die Benutzung der vom avr-gcc Compiler zur Verfügung gestellten 64-Bit-Integer Division ca. 4 kB kostet. Daher habe ich die float64-Bib. so geändert, dass, falls #define F_PREFER_SMALL_BUT_SLOWER_CODE oder #define F_PREFER_SMALLEST_BUT_SLOWEST_CODE vorhanden ist, eine eigene primitive Division verwendet wird, mit der man bis zu 4500 Bytes sparen kann. Dann ist die Performance der Division allerdings nur noch ca. 100 pro Sekunde bei F_PREFER_SMALLEST_BUT_SLOWEST_CODE oder 250 pro Sekunde bei F_PREFER_SMALL_BUT_SLOWER_CODE. Auch die math. Fkt. (exp, log, ...) sind dann langsamer. Außerdem ergibt in der neuen Version f_sqrt aus einer negativen Zahl korrekterweise NaN (komplexe Zahlen gibt es hier nicht).
Antwort schreiben
Die Angabe einer Email-Adresse ist freiwillig. Wenn Sie automatisch per Email über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.
Wichtige Regeln - erst lesen, dann posten!
- Suchfunktion und Betreffsuche benutzen - vielleicht gibt es schon einen ähnlichen Beitrag
- Aussagekräftigen Betreff wählen
- Im Betreff angeben um welchen Controllertyp es geht (AVR, PIC, ...)
- Groß- und Kleinschreibung verwenden
- Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang
- JPEG-Dateien (.jpg) nur für Fotos und Scans verwenden
- Schaltpläne, Screenshots usw. als PNG oder GIF anhängen
Formatierung (mehr Informationen...)
- [c]C-Code[/c]
- [avrasm]AVR-Assembler-Code[/avrasm]
- [pre]vorformatierter Text (z.B. Code in anderen Sprachen)[/pre]
- [math]Formel in LaTeX-Syntax[/math]
- [[Titel]] - Link zu Artikel


