Guten Morgen, ich nutze den gut abgehangenen ARM-GCC 5.4.1, aber die vorliegende Problematik dürfte sich nicht geändert haben. MCU ist ein Cortex M4F (STM32F446RE) und die float-Erweiterungen werden genutzt. Meine Beobachtung: Für kleine Eingangswerte ist die Funktion sinf() ziemlich schnell (grob 250 Takte), für große ( > 10*2*pi) wird sie aber ziemlich schnell langsam (> 2000 Takte). Wo kann ich ich mir den Quelltext der builtin-Funktionen anschauen, um der Sache auf die Schliche zu kommen? Gibt es irgendwo Informationen, bei welchen eingebauten Funktionen ich ebenfalls unerwartet massiv unterschiedliche Laufzeiten in Abhängigkeit der Eingabewerte erwarten muss? (Bei einem memcpy() oder printf() ist es nicht unerwartet, bei einem sinf() schon.)
Die Standard Funktionen der C Bilbiothek benutzen den Datentyp double, die FPU kann aber nur float. Es gibt alternative Funktionen, die du stattdessen benutzen kannst. Schau dir dazu diesen Absatz an, ich glaube der trifft 1:1 auch auf deinen STM32F446 zu: http://stefanfrings.de/stm32/stm32f3.html#fpu Das CPACR Register ist im "Programming Manual" beschrieben.
:
Bearbeitet durch User
Steve van de Grens schrieb: > Die Standard Funktionen der C Bilbiothek benutzen den Datentyp double sin() benutzt double, sinf() single precision float. Die FPU ist aktiv, sonst hätte ich noch ganz andere Taktzahlen.
Walter T. schrieb: > Wo kann ich ich mir den Quelltext der builtin-Funktionen anschauen, um > der Sache auf die Schliche zu kommen? In den gcc-Sourcen? Wenn sinf(Wert % 2*PI) erkennbar schneller ist als sinf(Wert), dann ist wohl was faul. Sonst eher nicht. Oliver
Hi Je nach verwendetet libc kann das aus unterschiedlichen Quellen kommen. Das hier https://sourceware.org/git/?p=newlib-cygwin.git;a=blob;f=newlib/libm/mathfp/sf_sine.c;h=8dd34d9a1dac27ecd3e3fce50264977edde88640;hb=refs/heads/master ist aber mit hoher Wahrscheinlichkeit das was du suchst. Matthias
Μαtthias W. schrieb: > Das hier > https://sourceware.org/git/?p=newlib-cygwin.git;a=blob;f=newlib/libm/mathfp/sf_sine.c;h=8dd34d9a1dac27ecd3e3fce50264977edde88640;hb=refs/heads/master > ist aber mit hoher Wahrscheinlichkeit das was du suchst. Besten Dank! Sogar mit zitiertem Lesestoff. Das muss ich mich heute abend mal in Ruhe zu Gemüte führen. Auf Anhieb finde ich nämlich nichts, was abhängig vom Funktionsparameter die Laufzeit ernsthaft beeinflussen könnte.
Walter T. schrieb: > sin() benutzt double, sinf() single precision float. Ja genau. Ich dachte dass für "große Werten" double Funktion verwendest hast. Wo man konkrete Angaben zum Timing findet weiß ich nicht.
Walter T. schrieb: > Auf Anhieb > finde ich nämlich nichts, was abhängig vom Funktionsparameter die > Laufzeit ernsthaft beeinflussen könnte. Rein technisch besteht der Knackpunkt darin, daß man für Winkelfunktionen nur Winkel in einer einzigen Vollperiode braucht und da zum Berechnen auch nur im ersten Quadranten. Folglich müssen ganze Perioden zuvor abgetrennt werden und dann alles auf eben diesen ersten Quadranten gefaltet werden - unter Vermerk, in welchem Quadranten der Winkel eigentlich lag. So ein Vorgeplänkel ist für allgemeine Winkelfunktionen immer nötig. Und darin liegt auch der Unterschied für verschiedene Input-Werte. W.S.
W.S. schrieb: > Und > darin liegt auch der Unterschied für verschiedene Input-Werte. Nicht nur. Die "sinf"-Implementation aus der Newlib hat auch noch als Optimierung drinnen dass sin(x)≅x, für kleine x. Spart eine Handvoll an float-Multiplikationen.
:
Bearbeitet durch User
W.S. schrieb: > Folglich müssen ganze Perioden zuvor abgetrennt werden und dann alles > auf eben diesen ersten Quadranten gefaltet werden - unter Vermerk, in > welchem Quadranten der Winkel eigentlich lag. Genau, und man sollte es mit der Größe der Argumente - gerade bei der kümmerlichen Genauigkeit von float - nicht übertreiben, sonst kann man auch einfach würfeln ... So findet man im steinalten MC68881 Manual: "If the source operand is not in the range of [-2*\pi ... 2*\pi], then the argument is reduced to within that range before ... is calculated. However, large arguments may lose accuracy during reduction, and very large arguments (greater than approximately 10^20) loose ALL accuracy." Und das war bei Register-Argumenten, also 80-Bit FP-Format. Wann das bei float zuschlägt, kann man sich dann auch überlegen ...
W.S. schrieb: > Folglich müssen ganze Perioden zuvor abgetrennt werden Ja, und im vorliegenden Quelltext wird das sehr geschickt gemacht, um keine Genauigkeit durch Skalierung zu verlieren. Da sehe ich nichts, was vom Funktionsparameter heftig abhängt. A. B. schrieb: > Wann das bei float zuschlägt, kann man sich dann auch überlegen .. Bei über 1000*2*pi.
:
Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.