Wenn ich in einem C Programm double nutze, die FPU aber nur float
unterstützt, profitiert der Code dann noch von der FPU oder ist sie in
diesem Fall unnütz?
Falls es eine Rolle spielt, soll sich die Frage auf den STM32F303 mit
arm-gcc und newlib-nano beziehen. Das ist nämlich mein konkreter Fall.
Nein, die FPU müßte von sich aus schon double unterstützen.
Auf der anderen Seite ist double auf M3/M4 Prozessoren schon sehr
schnell, sodaß es keinen Grund gibt, auf double zu verzichten, wenn man
es braucht.
Falls möglich, werden vom Compiler auch beim Rechnen mit Doubles
Instructions für eine Single FPU erzeugt. Natürlich wird das nicht immer
möglich sein.
P. S. schrieb:> Falls möglich, werden vom Compiler auch beim Rechnen mit Doubles> Instructions für eine Single FPU erzeugt.
Dann zeige mal ein einziges Beispiel. Ich bin gespannt ;-)
Ganz klar: Jein!
Ohne passende Bibliotheken, die die konkrete FPU unterstützen, wird das
nichts. Nur Hardware ändern, ändert an den Datentypen nichts.
Es ist aber nicht ausgeschlossen, dass eine FPU insgesamt, da auf
mathematische Berechnungen getrimmt, den "alten" Job schneller macht.
Float und Double ist auf µC meist keine Sinnvolle Lösung.
Der Vorteil liegt bei extrem Großer Dynamik
was bei unbekannten Signalen oder unbekannten Operationen hilfreich ist.
aber 12 Bit Analog oder 16Bit über CAN oder Zähler ist keine große
Dynamik
Auch weiß man i.f.R genau was zu rechnen ist.
Festkomma ist fast immer die beste Lösung.
Fließkomma oder Skalierung mit 10, 100 , 1000
ist immer ein guter Hinweis das der Entwickler die Sache nicht durch
gerechnet hat.
Sich mit Themen wie Auflösung, Toleranzen, Rundungen, Genauigkeit,
Fehlerrechnung, Überläufe...
nie Beschäftigt hat.
Und das fällt einem irgendwann schmerzhaft auf die Füße.
Stefanus F. schrieb:> Falls es eine Rolle spielt, soll sich die Frage auf den STM32F303 mit> arm-gcc und newlib-nano beziehen.
Bei ARM Cortex-M4F müsste man mit den ABIs spielen (soft, softfp, hard).
Mit der "hardware" float ABI könne man sich eine Handbremse einhandeln,
denn dort werden auch Double Werte über die FPU an Funktionen übergeben
(die anderen Fälle benutzen CPU Register).
Kann die FPU keine Doubles, müssen die Werte erst wieder aus der FPU
zurück an die CPU übertragen werden, was natürlich Zeit kostet.
Müsste der OP aber selbst überprüfen (z.B. mit 'nem Timer) was für ihn
am Schnellsten läuft.
Ich arbeite seit einigen Monaten an einem privaten Audio-DSP Projekt.
Hardware STM32F407. Also mit FPU.
Ich rechne Filter, Reverb-Algorithmen und Modelle in einer 96kHz
(10.4µs) Task und beobachte die Rechenzeiten der einzelnen Blöcke immer
mit.
Zuerst habe ich wie ich es bisher kannte mit Festkommaoperation
gearbeitet, bin dann aber auf float umgestiegen. Das war ein
Geschwindigkeitsvorteil, weil float oft genauso schnell berechnet wurde
wie int. Aber ich habe auf einige Skalierungen verzichten können.
Aber wehe ich haben irgendwo ein y= x * 3.14159265359; stehen. Das
fehlende f für float führt dazu, dass double verwendet wird. Dann geht
die Rechenzeit eines Filters schnell mal um Faktor 10 nach oben.
Volle schrieb:> Float und Double ist auf µC meist keine Sinnvolle Lösung.
Das gilt vielleicht für einen 8-Bitter.
Stefanus redet von einem 32-Bitter mit FPU.
ich hab mich auf 32bit bezogen (8 Bit Rechner hab ich 1992
ausgemustert)
Thema Auflösung und Rundung
da meinen viele irrtümlich das sei bei Fließkomma besser
und kümmern sich nicht darum.
Walter T. schrieb:> Audio Phil schrieb:>> Das>> fehlende f für float führt dazu,>> ...daß der Compiler eine Warnung ausspuckt, wenn man ihn läßt.
... oder es passiert überhaupt nichts aufregendes, weil man mit
-fsingle-precision-constant kompiliert
Christopher J. schrieb:> Walter T. schrieb:>> Audio Phil schrieb:>>> Das>>> fehlende f für float führt dazu,>>>> ...daß der Compiler eine Warnung ausspuckt, wenn man ihn läßt.>> ... oder es passiert überhaupt nichts aufregendes, weil man mit> -fsingle-precision-constant kompiliert
Diese primitive Lösung bei der double und float 32bit hat gibt es nur
bei den C/C++-Compilern der 8bit PICs und 8bit AVRs.
Die STMs können doubels problemlos auf der FPU berechnen. Wenn man
Atollic o.ä. benutzt wird auch automatisch die entsprechende Bibliothek
benutzt. Es gibt von ST einen Appnote dazu was wieviele Takte braucht.
Ich meine Double braucht genau ddoopelt so lange wie singel. Wobei
Addition Subtraktion Multiplikation und Cast einen bzw dann 2 Takte
brauchen. Und Wurzel und dividieren 8 bzw. 16. Wenn es mehr Performance
braucht geh zum H7 der hat eine DP FPU.
Wie ihr an der Frage korrekt erkannt habe, habe ich
Fließkomma-Operationen auf Mikrocontrollern praktisch keine Erfahrung.
Auf 8bit µC habe ich gelernt, weitgehend mit Integer Datentypen
auszukommen.
Nun habe ich aber inzwischen auch einige STM32F303 Board in der
Bastelkiste. Die haben eine FPU und deswegen ist das Thema
"Fließkomma-Arithmetik" wieder hoch gekommen. Float ist allerdings
manhcmal zu ungenau, daher meine Frage. Wenn der Unterschied zu Double
gering wäre, würde ich einfach immer double nehmen - so handhabe ich das
im Job (Server Backend).
auf µC gilt Datentypen so klein wie möglich und so groß wie nötig
aus Bequemlichkeit pauschal double zu verwenden geht nicht lange gut.
Autofahren nur mit dem 5. Gang macht innerorts keinen Spass.
Und damit komme ich wieder zum Thema das man genau wissen sollte was
sman macht bezüglich Aufösung Genauigkeit...
Stefanus F. schrieb:> Wie ihr an der Frage korrekt erkannt habe, habe ich> Fließkomma-Operationen auf Mikrocontrollern praktisch keine Erfahrung.
Dass du keine Ahnung hast brauchst du nicht ständig betonen. Weiß hier
jeder.
Boris schrieb:> Dass du keine Ahnung hast brauchst du nicht ständig betonen. Weiß hier> jeder.
Danke fürs Nachtreten. Das war sehr weise und hilfreich.
Helmut S. schrieb:> Christopher J. schrieb:>> Walter T. schrieb:>>> Audio Phil schrieb:>>>> Das>>>> fehlende f für float führt dazu,>>>>>> ...daß der Compiler eine Warnung ausspuckt, wenn man ihn läßt.>>>> ... oder es passiert überhaupt nichts aufregendes, weil man mit>> -fsingle-precision-constant kompiliert>> Diese primitive Lösung bei der double und float 32bit hat gibt es nur> bei den C/C++-Compilern der 8bit PICs und 8bit AVRs.
-fsingle-precision-constant bewirkt eben nicht, dass double äquivalent
zu float ist, sondern nur dass Konstanten (auch ohne angehängtes f) als
float behandelt werden. Hier mal ein Beispiel:
https://godbolt.org/z/CL6fiQ
Stefanus F. schrieb:> Auf 8bit µC habe ich gelernt, weitgehend mit Integer Datentypen> auszukommen.
Das sind die alten Vorurteile aus den 70/80ern. Aber selbst der PET hat
schon mit 40 Bit Fließkommazahlen gearbeitet.
Seit AVR habe ich gelernt, wenn ich float brauche nehme ich float. Und
wenn ich dort double brauche, dann nehme ich auch double. Was soll der
Geiz?
> Float ist allerdings> manchmal zu ungenau, daher meine Frage. Wenn der Unterschied zu Double> gering wäre, würde ich einfach immer double nehmen - so handhabe ich das> im Job (Server Backend).
Nimm double, wenn Du double brauchst. Ausführungszeiten habe ich Dir ja
oben verlinkt. Und wenn es doch noch schneller gehen soll und float
ausreicht, aktiviere die FPU und rechne damit. Bezahlt ist das Teil ja
schon ;-)
Und wie oben auch erwähnt, gibt es die H7xx, die die Grundrechenarten
beider Typen per Hardware rechnen. Klein und günstig STM32H730/750, wenn
man nicht dem Flash-Wahn erlegen ist.
m.n. schrieb:> P. S. schrieb:>> Falls möglich, werden vom Compiler auch beim Rechnen mit Doubles>> Instructions für eine Single FPU erzeugt.>> Dann zeige mal ein einziges Beispiel. Ich bin gespannt ;-)
Ein naheliegender Fall wären mathematische Funktionen, die ihr Ergebnis
schrittweise approximieren (z.B. mittels Newtonverfahren), bis die
gewünschte Genauigkeit erreicht ist. da könnte man die ersten Schritte
mit float rechnen, auch wenn man später ein double-Ergebnis will.
Inwiefern das tatsächlich gemacht wird, weiß ich allerdings nicht. SDCC
unterstützt ja kein double und keine FPU.
Philipp Klaus K. schrieb:> da könnte man die ersten Schritte> mit float rechnen, auch wenn man später ein double-Ergebnis will.>> Inwiefern das tatsächlich gemacht wird, weiß ich allerdings nicht.
Wer so programmiert, hat einen an der Waffel!
Ein Programm soll ein Problem lösen und nicht neue Fallstricke schaffen.
Wenn sich hier Leute melden, deren Programm angeblich zu langsam läuft,
dann liegt das nicht an den verwendeten Datentypen, sondern an
ungeschickter Programmierung oder noch schlimmer, an Funktionen wie
delay_ms(100).
m.n. schrieb:> Philipp Klaus K. schrieb:>> da könnte man die ersten Schritte mit float rechnen,>> auch wenn man später ein double-Ergebnis will.>>>> Inwiefern das tatsächlich gemacht wird, weiß ich>> allerdings nicht.>> Wer so programmiert, hat einen an der Waffel!
Nein: Der hat Ahnung von Numerik.
Aber sei unbesorgt: Das trifft auf die allermeisten
Programmierer nicht zu. Keine Gefahr.
Philipp Klaus K. schrieb:> Inwiefern das tatsächlich gemacht wird, weiß ich> allerdings nicht.
Es gab mindestens einen Signalprozessor, der das
unterstützt hat. Typ weiss ich nicht. Dort gab es eine
schnelle "ungefähre" Division und einen Extrabefehl,
um mittels Fixpunktiteration die restlichen Stellen
zu beschaffen.
Stefanus F. schrieb:> Wenn ich in einem C Programm double nutze, die FPU aber nur float> unterstützt, profitiert der Code dann noch von der FPU oder ist sie in> diesem Fall unnütz?
Soweit ich es kenne, gibt es keine unmittelbare Möglichkeit die 32-Bit
IEEE FPU für Doubles zu nutzen.
Grundsätzlich kann sie aber schon als Basis für Berechnungen höherer
Genauigkeit dienen. Dies wird (wurde?) beim Supercomputing gemacht, bei
Archtikturen die GPUs nutzen. Stichwort float-float operators. Z.B.
https://hal.archives-ouvertes.fr/hal-00021443/documenthttp://andrewthall.org/papers/df64_qf128.pdf
Egon D. schrieb:> Es gab mindestens einen Signalprozessor, der das> unterstützt hat. Typ weiss ich nicht. Dort gab es eine> schnelle "ungefähre" Division und einen Extrabefehl,> um mittels Fixpunktiteration die restlichen Stellen> zu beschaffen.
mindestens, weiss ich nicht, ungefähr, ...
Na das ist ja alles sehr konkret.
Ein Spezialfall soll nun die Standardlösung für jede numerische
Berechnung sein? Und das, wo viele F7xx und alle H7xx µCs von Hause aus
schon double Berechnungen per Hardware bieten? Und es gibt nach andere
Anbieter ...
Ich sag nur: Bahlsen!
Wie in einem anderen Thread rausgefunden haben die F76x und F77x eine
DFPU.
Nur zur Präzision ;)
Ansonsten sehe ich das nicht so, dass eine FPU doubles beschleunigen
kann.
Das ist ja nicht wie bei einem fixkomma add mit 64bit wo es reicht ein
normales add und danach ein add with carry auszuführen.
Selbst ein 64bit MUL geht mit 3 32Bit MULs und einer Abfrage.
f32 und f64 sind komplett anders aufgebaut.
Das f64 müsst man also erstmal entpacken, dann gucken obs beschleunigbar
wäre und diesen Teil wieder nach f32 packen damits die FPU auch
versteht.
Da kann mans dann auch gleich direkt mit dem integer Teil der CPU
rechnen.
Im Disasm sieht der pack/entpack Teil der f64 lib viel größer aus als de
eigentliche Rechenteil.
Wie eine FPU addiert hab ich mal als pdf in den Anhang gepackt.
Das sind ja auch eure Steuergelder ;)
m.n. schrieb:> Ein Spezialfall soll nun die Standardlösung für jede numerische> Berechnung sein?
Hat doch keiner gesagt. Im Rahmen meiner fand ich diese Idee durchaus
für passend, obwohl mir klar war, dass es nur ein Spezialfall ist.
Mw E. schrieb:> Das ist ja nicht wie bei einem fixkomma add mit 64bit wo es reicht ein> normales add und danach ein add with carry auszuführen.> Selbst ein 64bit MUL geht mit 3 32Bit MULs und einer Abfrage.
Das war mein Gedanke dahinter. Wenn man große Integer Operationen in
kleine zerlegen kann, dann vermutlich auch mit Fließkommazahlen. Nur war
mir halt nicht klar, ob sich dann die Nutzung der kleinen FPU überhaupt
noch lohnt.
Stefanus F. schrieb:> Im Rahmen meiner fand ich diese Idee durchaus> für passend, obwohl mir klar war, dass es nur ein Spezialfall ist.
Dann sag doch, was genau Du rechnen willst.
Deine Frage war allgemeiner Natur und nichts Spezielles und erst recht
nichts Zeitkritisches.
m.n. schrieb:> Dann sag doch, was genau Du rechnen willst.
Kann ich leider nicht. In diesem Thread geht es mir nicht um eine Lösung
für ein konkretes Problem, sondern darum, den Sachverhalt zu verstehen.
Bisher bin ich immer mit Integer ausgekommen. Doch in Zukunft, wenn
float oder double "billig" ist, werde ich mir wohl einige Klimmzüge zur
Nutzung von Integer sparen.
Für mich ist die eigentliche Frage eher: Nehme ich dann float oder
double?
Da ich nun verstehe, dass double nicht von der kleinen FPU profitiert,
kommt also wohl nur float in Frage. Wo das nicht genügt würde ich dann
doch wieder lange Integer verwenden.
> Deine Frage war allgemeiner Natur und nichts Spezielles> und erst recht nichts Zeitkritisches.
Ja stimmt. Die Idee, sich per Float an einen Wert anzunähern und dann
erst genauer weiter zu rechnen ist für mich aber auch interessant. Denn
einen Annäherungs-Algorithmus hatte ich mal auf einem ATmega16
gebraucht.
In diesem Fall ging es darum, einen fahrenden Roboter sanft zu bremsen,
wofür ich fortlaufend den verbleibenden Bremsweg schätzen musste. Da war
die sqrt() Funktion zu schwergewichtig. Mit FPU würde ich jedoch nochmal
sqrt() versuchen, weil es einfacher wäre.
Deswegen interessiert mich der Aspekt schon, den Egon da ansprach.
Stefanus F. schrieb:> Da ich nun verstehe, dass double nicht von der kleinen FPU profitiert,> kommt also wohl nur float in Frage. Wo das nicht genügt würde ich dann> doch wieder lange Integer verwenden.
Gut, dann bleib bei Deinen Vorurteilen, daß Fließkommaverarbeitung
langsam und damit böse ist. Es ist ja nichts Neues, daß u.a.
float/double bei vielen µC Anwendern Einnässen auslöst.
Stefanus F. schrieb:
> Da ich nun verstehe, dass double nicht von der kleinen FPU profitiert,> kommt also wohl nur float in Frage.m.n. schrieb:> Gut, dann bleib bei Deinen Vorurteilen, daß> Fließkommaverarbeitung langsam und damit böse ist.
Ich habe kein Vorurteil. Wie kommst du überhaupt auf den Schluss, dass
"kommt wohl nur float in Frage" für mich bedeutet, dass
"Fließkommaverarbeitung langsam und damit böse" sei?
Ich habe doch gerade erst angekündigt, float benutzen zu wollen!
Tschuldigung, aber dein Schluss entbehrt jeder Logik.
Für mich ist ein Programm optimal wenn es gut zu verstehen ist und damit
wartbar ist, das ist mir um Längen wichtiger als kürzest mögliche
Ausführungszeit. Also erstmal einfach und verständlich programmiert,
dann wenn nötig optimieren und nicht gleich alles dem Performancegott
opfern.
Fehler kann man mit jedem Datentypen machen, alle haben ihre Tücken. Wer
mir sagt das er als Anfänger da nie drauf reingefallen ist dem glaube
ich nicht. Bei Integer kann man auch ruck zuck Überläufe erzeugen, z.B.
eine lange Berechnung und das Zwischenergebnis wird zu groß. In C/C++
wird sowas nicht abgefangen und ein vermeintlich funktionierendes
Programm macht irgendwann Blödsinn.
Float skaliert sich durch die Normierung automatisch, aber bei Addition
kleiner Werte auf Große muss man genauso aufpassen. Schönes Beispiel ist
die Berechnung der Standardabweichung wo durch Addition der Quadrate
schnell große Summen entstehen.
Trotzdem reichen floats in vielen Berechnungen die man mit µC macht.
Hier war mal PID Berechnung das Thema, ich habe es auf dem STM32F407
gemessen und die float Rechnung brauchte 0,54 µs. Da lohnt es sich wohl
kaum das mit Integer und Klimmzügen optimieren zu wollen.
Nur bei den M0 muss man gut aufpassen, eine Mul wie
1
x*=10.0;
erzeugt sofort vielmehr Code wenn double ins Spiel kommen. Bei der
Umsetzung von AVR-Arduino Libs läuft man da schnell rein weil die AVR
Programmierer den Unterschied nicht beachten mussten.
Mal wieder ein typisch sinnlos zerpflückter Text. Die Frage war: Bewirkt
beim Cortex M4F die FPU eine Beschleunigung. Ich halte die Frage für
halbwegs berechtigt.
Nicht komplett berechtigt, weil ich bei einem Quelltext, der
64-Bit-Float benutzt, sicherlich auch an anderen Stellen 32-Bit-Float
benutze, und schon allein deswegen die FPU-Unterstützung auf jeden Fall
einschalte. Also wird der Vergleich wohl kaum M4 gegen M4F beinhalten.
Aber die Frage impliziert ja auch: "Wieviel ist ein M4 schneller als ein
M3 bei double-Berechnungen?" Und das ist durchaus interessant.
Audio Phil schrieb:> In 5 Minuten hast Du das doch selbst ausprobiert. Einmal mit, einmal> ohne FPU kompiliert.
Da hast du wohl Recht. Ich hätte es auch ausprobieren können. Allerdings
neige ich dazu, das Testergebnis für allgemein gültig zu halten. Solche
Diskussionen hier helfen mir, das Thema differenzierter zu betrachten.
chris schrieb:> Wieso schreibt Ihr nicht einfach einen Benchmark und stellt den> hier rein?
Habe ich doch gerade erst erklärt:
Stefanus F. schrieb:> neige ich dazu, das Testergebnis für allgemein gültig zu halten. Solche> Diskussionen hier helfen mir, das Thema differenzierter zu betrachten.
Volle schrieb:> Festkomma ist fast immer die beste Lösung.
Prust.
Nur weil die ADCs und DACs 16bittig sind, heißt das noch lange nicht,
daß in der Rechnung keine größere Dynamik benötigt wird.
Ich hatte z.B. bei einer PID-Regelung ständig mit Rundungsfehlern und
Überläufen zu kämpfen. Nach der Umstellung auf float lief sie perfekt.
Als ich mein Wirkleistungsmessgerät das erste mal ans Netz gehangen habe
wurden die ADC Werte auch so groß, dass mir mein Fixkomma um die Ohren
geflogen ist.
Nunja, jetzt sinds eben uint64_t ;)
(I/U RMS Berechnung über Aufsummierung)
Da der M3 keine FPU hat bleibt das auch erstmal so.
Eine single precision FPU nützt für double precision leider nichts.
Berechnungen mit double erzeugen trotzdem Aufrufe in die EABI und werden
durch die CPU emuliert. Je nachdem was man tun möchte kann man aber mehr
Präzision aus einer single precision FPU herausholen, indem man mehrere
Variablen nutzt.
Als Beispiel für Addition das Kahan/Neumeier Verfahren:
https://en.wikipedia.org/wiki/Kahan_summation_algorithm
Mit ähnlichen Tricks kann man sich double oft sparen. Im Vergleich zur
Software Emulation von double bietet die FPU Nutzung dann erhebliche
Geschwindigkeitsvorteile.
Es gibt tatsächlich noch eine Möglichkeit, double als Summe zweier float
effizient zu implementieren. Man erhält dabei zwar keinen IEEE double
(selbst wenn man einen IEEE float hat), aber einen double, der dem
C-Standard (siehe Abschnitt 5.2.4.2.2 im aktuellen ISO C17) entspricht.
Damit erhält man etwa die Genauigkeit eines "normalen" double, aber
gwinnt ist bezüglich der größtmöglichen und kelinstmöglichen
darstellbaren Zahlen kaum etwas (man hat also etwa die Mantisse wie bei
einem double, aber der Wertebereich des Exponenten bleibt etwa wie bei
einem float).
Ob dies in aktuellen Compilern verwendet wird, weiß ich nicht.
Verbreitet ist oder war aber die analoge Implementierung eines 128-bit
long double auf Hardware, die nur 64-bit double unterstützt.
Siehe:
T.J. Dekker, "A floating-point technique for extending the available
precision" in Numerische Mathematik, Band 18, Heft 3, Seiten 224, 242,
Springer, 1971.