Forum: Compiler & IDEs Lahme mathlib für STM32F411


von Mike (Gast)


Lesenswert?

Ich habe gerade mal die Geschwindigkeit der sinf() - Funktion mit 
folgndem Progrämmchen getestet:
1
  volatile float f = 0.0f;
2
  float phi = 0.0f;
3
  float dphi = 0.1f;
4
  volatile uint32_t start, dt;
5
  start = uwTick;
6
  for (uint32_t i=0; i< 100000;i++) {
7
   f += sinf(phi);
8
   phi += dphi;
9
  }
10
  dt = uwTick - start;
Die volatile sind notwendig, damit der Compiler die Schleife nicht 
wegoptimiert. dt enthält die vergangene Zeit in Millisekunden.
Bei 48MHz CPU-Takt bekomme ich dt= 5948 ms. Ersetze ich den Ausdruck 
sinf(phi) durch phi, braucht der STM nur 33ms. Daraus folgt, dass eine 
Sinusfunktion 59µs, also über 2800 Takte benötigt. Wie kann das sein?
Meine Vermutung ist, dass die Mathematikbibliothek die 
Gleitkommahardware nicht nutzt. Leider habe ich keinen Sourcecode.

Die Hardware floating point unit ist aktiviert (-mfloat=abi-hard), die 
Linker-Option -lm ist aktiv.

von DerEinzigeBernd (Gast)


Lesenswert?

Mike schrieb:
> Leider habe ich keinen Sourcecode.

Welcher Compiler ist das?

von Mike (Gast)


Lesenswert?

DerEinzigeBernd schrieb:
> Welcher Compiler ist das?

gcc mit der Cube IDE. Interessanterweise ist es sogar geringfügig 
schneller, wenn man float durch double und sinf durch sin ersetzt.
Ich habe den bösen Verdacht, dass sinf auf sin zurückgreift.

von PittyJ (Gast)


Lesenswert?

Was erwartest du denn?
Soll die FPU den Sinus in einem Takt berechnen? Das geht doch gar nicht.
Wenn du dir mal die FPU anschaust, dann sind dort keine Operationen 
enthalten, die irgendeine trigonometrische Funktion direkt berechnen.

https://developer.arm.com/documentation/ddi0439/b/Floating-Point-Unit/FPU-Functional-Description/FPU-instruction-set?lang=en
Tabelle 7.1

Der Sinus muss also von Hand berechnen werden, und FPU unterstützt den 
Algorithmus mit den 4 Grundrechnenarten auf Floating Point Zahlen.

Dann wird evtl so etwas wie ein Cordic-Algorithmus benutzt, ähnlich 
diesem hier:
https://www.mikrocontroller.net/articles/AVR-CORDIC

Da sind doch einige Berechnungen in einer Schleife drin.

von STM Apprentice (Gast)


Lesenswert?

Wenn man schon einen F411 hat dann lässt man den auch mit
seiner maximalen Taktrate arbeiten, das sind dann 100 MHz
oder - um optimale Taktkonfigurationen zu erreichen - zum
Beispiel 96 MHz.

von Hans-jürgen H. (hjherbert) Benutzerseite


Angehängte Dateien:

Lesenswert?

Versuchs mal mit diesem Unterprogramm und berichte das Ergebnis.

: Bearbeitet durch User
von PittyJ (Gast)


Lesenswert?

Hans-jürgen H. schrieb:
> Versuchs mal mit diesem Unterprogramm und berichte das Ergebnis.

ist schon interessant. Da wird mit Standard Float gerechnet (also nicht 
double), und bei der Konstanten
0.15915494309189533576888376337251F
werden 32 Nachkommastellen angegeben.

Bei IEEE-754 werden für Single-Precision 23 Bit Mantisse benutzt, was 
dann ca 7 Dezimalstellen bedeutet.

von Bauform B. (bauformb)


Lesenswert?

Mike schrieb:
> Die Hardware floating point unit ist aktiviert (-mfloat=abi-hard),
> die Linker-Option -lm ist aktiv.

reicht das, damit der Linker die richtige math lib benutzt? Ich 
glaube, ich hab' noch -march=armv7e-m+fp und/oder -mfpu=fpv4-sp-d16 
gebraucht.

von W.S. (Gast)


Lesenswert?

PittyJ schrieb:
> Bei IEEE-754 werden für Single-Precision 23 Bit Mantisse benutzt, was
> dann ca 7 Dezimalstellen bedeutet.

Eigentlich sollten es 24 Bit sein. Vielleicht hast du beim Zählen das 
Hiddenbit vergessen.

Also 6 ms für den Sinus bei einem 50 MHz Cortex will auch mir schon 
etwas arg langsam vorkommen. Zum Vergleich: mit dem Pedersen braucht man 
nach der Quadrantenseparation 3 Additionen, 3 Multiplikationen und 1 
Division. Da sollte der Sinus im unteren µs Bereich erledigt sein. Und 
für etwa 7 Dezimalstellen reicht der auch.

W.S.

von Malte _. (malte) Benutzerseite


Lesenswert?

Mike schrieb:
> Leider habe ich keinen Sourcecode.
Einfach die .elf durch den Disassembler jagen und schauen was drinne 
ist:
arm-none-eabi-objdump -d Input.elf > output.disassembly

In der sin Funktionen sollten dann recht offensichtlich sein, ob da die 
Floatingpoint Unit genutzt wird.

: Bearbeitet durch User
von Dieter (Gast)


Lesenswert?

Hier gibts eine Sinus-Implementierung direkt in Assembler für die 
Cortex-M4 FPU:

https://github.com/vpecanins/cortex-m4f

von Walter T. (Gast)


Lesenswert?

sinf(phi) wird lahm für große phi. Die Rückskalierung auf den Bereich 
0...pi scheint recht aufwendig zu sein.

von W.S. (Gast)


Lesenswert?

Walter T. schrieb:
> Die Rückskalierung auf den Bereich
> 0...pi scheint recht aufwendig zu sein.

Eigentlich nicht. Wenn man das Ganze auf den Bereich 0..4 skaliert 
(genauer 0<=x<4), dann kostet das nur eine Multiplikation und schon hat 
man den Quadranten im ganzen Teil und den Restwinkel im gebrochenen 
Teil. Zum anschließenden Auseinandernehmen ist allerdings etwas 
Assembler dabei.

Natürlich kann man's auch viel umständlicher machen.

W.S.

von Walter T. (Gast)


Lesenswert?

W.S. schrieb:
> Wenn [...]

Die Implementation der libc ist einschlägig und man kann auch nachsehen 
anstelle zu raten.

Die Entwickler haben sich viel Mühe gegeben, dass große Argumente keinen 
vorzeitigen Auflösungsverlust ergeben, und das kostet Rechenzeit.

Und umgekehrt bedeutet das, dass Benchmarking von sinf() unbedingt im 
Ziel-Wertebereich erfolgen sollte, ansonsten ist die 
Rechenzeit-Abschätzung grob falsch.

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
Noch kein Account? Hier anmelden.