sprintf: was ist falsch?

OP #5927834
Lesenswert?

Guten Tag!

Ich habe immer selbst gebaute Funktionen für Ausgabe benutzt. Nun wollte 
ich sprintf ausprobieren.
1
#include <avr/io.h>
2
#include <math.h>
3
#include <stdio.h>
4

5
#include "main.h" 
6

7
char buff[20] = {0};
8
char b = 0;
9

10
int main(void){
11

12
asm volatile("nop");
13
b = sprintf(buff, "%f", 12.234657);
14
asm volatile("nop");
15

16
return 0;
17
}
In buff bekomme ich '?', d.h. 0x3f. In b, wie auch sein sollte, 1.
Ich habe aber für anderes in buff gerechnet.
Was fehlt hier noch?

mit "%d" und integer bekomme ich richtige Ausgabe. Aber min "%f" will 
sprintf nicht arbeiten.

Vielen Dank für die Antwort im voraus!
Gast #5927838
Lesenswert?

oftmals muss man gesondert angeben, dass man Floating-Point will. In den 
Compiler-Options oder auch bei der Auswahl der zu linkenden Library.

Floating point ist für Micro-Microkontroller halt aufwendig.
Gast #5927860
Lesenswert?

Maxim B. schrieb:
> Arduino Fanboy D. schrieb:
> Die ersten beiden Antworten nochmal lesen.
> So oft, bis verstanden.
>
> Danke für Info. Sehr hilfreich.

Wenn dich drei Leute bereits auf das selbe hinweisen und du es nicht 
verstehst, solltest du vllt erst Mal über dich selber nachdenken.
Gast #5927868
Lesenswert?

Maxim B. schrieb:
> Deine Antwort enthält sehr viel
> nutzbarer Information.

Deine Frage auch!

Mein heiß geliebtes Arduino möchte zur Aktivierung des %f in printf 
folgende Zeile in der betreffenden platforms.local.txt sehen:
> compiler.c.elf.extra_flags=-Wl,-u,vfprintf -lprintf_flt -lm
Wie du es deinem geheimen System vorkauen musst, kann ich dir nicht 
sagen.
OP #5927879
Lesenswert?

Arduino Fanboy D. schrieb:
>> compiler.c.elf.extra_flags=-Wl,-u,vfprintf -lprintf_flt -lm
> Wie du es deinem geheimen System vorkauen musst, kann ich dir nicht
> sagen.

Auch mit -lm nichts geändert.

Vielleiicht sollte ich noch Version von GCC sagen: 5.4.0

Auch die Frage: wie kann das sein, dass float alle Operationen korrekt 
lassen, nur mit sprintf das Problem? Wäre float nicht aktiviert, so 
könnte sicher auch Multiplizieren nicht gelingen oder?
Gast #5927891
Lesenswert?

Maxim B. schrieb:
> Auch die Frage: wie kann das sein, dass float alle Operationen korrekt
> lassen, nur mit sprintf das Problem? Wäre float nicht aktiviert, so
> könnte sicher auch Multiplizieren nicht gelingen oder?

Du hast die Doku noch nicht gelesen:
https://www.nongnu.org/avr-libc/user-manual/group__avr__stdio.html#gaa3b98c0d17b35642c0f3e4649092b9f1

Da steht: (ich lese es dir mal vor)

Since the full implementation of all the mentioned features becomes 
fairly large, three different flavours of vfprintf() can be selected 
using linker options. The default vfprintf() implements all the 
mentioned functionality except floating point conversions. A minimized 
version of vfprintf() is available that only implements the very basic 
integer and string conversion facilities, but only the # additional 
option can be specified using conversion flags (these flags are parsed 
correctly from the format specification, but then simply ignored). This 
version can be requested using the following compiler options:

    1 -Wl,-u,vfprintf -lprintf_min
If the full functionality including the floating point conversions is 
required, the following options should be used:
#5927913
Lesenswert?

Maxim B. schrieb:
> Kannst du bitte sagen, welche? Wie heißt sie, wo sie ist?

Du hast sie bereits angeschaltet:

Maxim B. schrieb:
> -lprintf_flt
> -lm
> -Wl,-u,vfprintf

Wenn es also noch immer nicht funktioniert, dann liegt das daran, dass 
diese Parameter nicht benutzt werden. Das können wir von hier nicht 
feststellen, also prüfe deine Umgebung.

Du kannst zum Testen ja ein "-fkjdsfhdylfgdl" ranhängen.
Das muss einen Fehler bringen.
#5927915
Lesenswert?

Maxim B. schrieb:
> Arduino Fanboy D. schrieb:
>> Oder einfach mal die Doku lesen, da stehts auch drin....
>>
> 
https://www.nongnu.org/avr-libc/user-manual/group__avr__stdio.html#gaa3b98c0d17b35642c0f3e4649092b9f1
>
> Dort steht nichts anderes als im Buch von Herbert Schildt. Aber die
> Beispiele von Schildt arbeiten auch nicht korrekt.

Das Buch von Schildt enthält Infos darüber, wie man bei der von dir 
geheim gehaltenen Toolchain Floatingpoint-Support für printf 
aktiviert? Das würde mich sehr wundern.

Maxim B. schrieb:
> Arduino Fanboy D. schrieb:
>>> compiler.c.elf.extra_flags=-Wl,-u,vfprintf -lprintf_flt -lm
>> Wie du es deinem geheimen System vorkauen musst, kann ich dir nicht
>> sagen.
>
> Auch mit -lm nichts geändert.
>
> Vielleiicht sollte ich noch Version von GCC sagen: 5.4.0

Und jetzt noch, für welche Zielplattform…

> Auch die Frage: wie kann das sein, dass float alle Operationen korrekt
> lassen, nur mit sprintf das Problem? Wäre float nicht aktiviert, so
> könnte sicher auch Multiplizieren nicht gelingen oder?

Weil -lm nur die Float-Bibliothek dazu linkt und nicht printf austauscht 
durch eins, das float unterstüzt. Dazu sind die anderen Optionen da. 
Aber wenn die bei dir nicht funktionieren, ist entweder was kaputt, oder 
du nutzt eine andere Toolchain, bei der die Optionen anders lauten 
müssen.

Arduino Fanboy D. schrieb:
> S. R. schrieb:
>> Wenn er des Englischen nicht mächtig ist, dann hilft das leider nicht
>> viel.
>
> Ich glaube, es hakt an anderer Stelle.

Den Eindruck habe ich auch.
OP #5927923
Lesenswert?

S. R. schrieb:
> Maxim ist ein Organist, der ein bisschen mit AVR bastelt.
> Kein bisschen Ingeneurshintergrund.

Ja. Einfach etwas Abschaltung von Musik. Das macht mir viel Spaß. Viel 
mehr Ahnung habe ich für Klavier- und Orgelbau und -Stimmung.

Z.Z überlege ich, ob es möglich ist mit meinen Vorkenntnissen, 
TLA-Stimmgerät nachzubauen (wer das Gerät nicht kennt: es kostet wie 
zwei Laptops. ich habe zwar ein, aber...). Dort sind float und double 
sehr wichtig. Eine Experimentierplatine für ATMEGA1284P habe ich mir 
entworfen, mit JTAG, nach Modulprinzip, so kann ich lange damit 
experimentieren.

Leider sind ansonsten bequeme billige Platten von Arduino Mega2560 kaum 
zu gebrauchen: dort sind wie mit Absicht von allen vier USART keine 
XCK-Leitungen gemacht. D.h. USART kann man nicht in SPI-Mode benutzen.
Beitrag #5927926 wurde von einem Moderator gelöscht.
OP #5927958
Lesenswert?

Rolf M. schrieb:
> Oft kommt
> man mit Festkommaarithmetik schon sehr weit.

Das stimmt. Aber manchmal gibt es genug Zeit und man kann bequemere 
Variante wählen.

Als Beispiel: Frequenzmeter (ein Stimmgerät ist nichts anderes als ein 
Frequenzmeter mit guter Auflösung für Schallfrequenzen. 0,001 Hz ist 
gute Wert, schlechter als 0,03 Hz darf das nicht sein). Man macht eine 
Messung, dann wird gerechnet. Dann wieder eine Messung. Dabei ist nicht 
so wichtig, wird 3mal pro Sekunde gemessen oder nur 2,9mal. So hat man 
mehrere Millisekunden für Rechnen.
Persönliche Seite #5927969
Lesenswert?

Maxim B. schrieb:
> Auch mit -lm nichts geändert.

-lm ist überflüssig, das gibt der Compiler ohnehin dem Linker mit.  Und 
zwar immer (außer mit -nostdlib).

> Wäre float nicht aktiviert, so könnte sicher auch Multiplizieren
> nicht gelingen oder?

float-Multiplikation ist Teil des Sprachkerns, das kann man weder 
aktivieren noch deaktivieren, und math.h braucht's auch nicht dazu.

Im Gegensatz dazu kommen sinf(), sprintf() etc. aus Bibliotheken und 
sind in Headern deklariert, der Sprachkern braucht nix davon zu wissen. 
Alles was zu wissen ist, ist das Interface beim Aufruf, und das steht im 
jeweiligen Header.


Maxim B. schrieb:
> TLA-Stimmgerät [...] Dort sind float und double sehr wichtig.

double ist bei avr-gcc nicht standardkonform so wie float implementiert, 
also nur 32 Bits lang.

Ja nachdem, welche Operationen gebraucht werden und wie der 
erforderliche Wertebereich ist, kann Fixed-Point basierend auf uint64_t 
oder uint32_t in Betracht gezogen werden, evtl. auch Fixed-Point aus 
stdfix.h.

Dazu müsste man aber erst die benötigten Operationen / Algorithmen 
kennen.
OP #5927971
Lesenswert?

Johann L. schrieb:
> Dazu müsste man aber erst die benötigten Operationen / Algorithmen
> kennen.

Deshalb bin ich hier in Forum :) Um mehr zu wissen. Ich habe zwar vier 
Diplome, aber alle sind musikalisch. Technik muß ich selber lernen.

Ich freue mich sehr, daß hier in Forum auch die Menschen sind, die sich 
die Mühe nicht sparen, etwas zu erklären.

Das mit sprintf, was gelöst wurde - das brauche ich nicht unmittelbar 
für ein Stimmgerät oder so was ähnliches. Dort benutz man besser andere 
Ausgabeformen (Man gibt Abweichung in Cent aus oder/und per Stroboskop). 
Aber ich möchte besser Standardbibliotek kennen. Ich möchte gut 
verstehen, wie alles funktioniert.


Beitrag "64 Bit float Emulator in C, IEEE754 compatibel"
#5928009
Lesenswert?

Maxim B. schrieb:
>> Dann kannst du den ATMega nicht benutzen, denn der kann kein double.
> Doch! ich habe hier in Forum eine Bibliothek gefunden!

Äh, nein. Der AVR kann kein double. Die avr-libc kann auch kein double.

> Dort sind double mit Hilde von u64 gemacht.

Dann ist das Fließkommaarithmetik auf u64, kein double.

Das funktioniert nicht mit den normalen Bibliotheken, auch nicht mit 
printf!

Das ist ein Unterschied!
#5928015
Lesenswert?

S. R. schrieb:
> Maxim B. schrieb:
>>> Dann kannst du den ATMega nicht benutzen, denn der kann kein double.
>> Doch! ich habe hier in Forum eine Bibliothek gefunden!
>
> Äh, nein. Der AVR kann kein double.

Er hat keine FPU, die das direkt in Hardware macht. Aber natürlich ist 
es möglich, sowas für den AVR in Software zu implementieren. Es wurde in 
der avr-libc nur nicht gemacht.

S. R. schrieb:
> Dann ist das Fließkommaarithmetik auf u64, kein double.

Es ist das double, das in IEEE 754 spezifiziert ist, nicht der 
C-Datentyp double.

> Das funktioniert nicht mit den normalen Bibliotheken, auch nicht mit
> printf!

Allerdings. Mit dem obigen sprintf("...%f...") kann man das nicht 
ausgeben.
OP #5928026
Lesenswert?

S. R. schrieb:
> Das funktioniert nicht mit den normalen Bibliotheken, auch nicht mit
> printf!
>
> Das ist ein Unterschied!

Ja, wenn ich solche double so wie sie sind auf LCD zeigen möchte, dann 
sollte ich selber eine Funktion machen... Nichts unmögliches. Wenigstens 
habe ich integer bisher auch so ausgegeben. Eigengemachte hex-dec ist 
auch viel sparsamer, als sprintf, da addieren und subtrahieren mit AVR 
viel schneller geht als dividieren.
Etwa so:
1
void hex_dec(int zahl, char *puff){
2
     char a=0, b=0, c=0, d=0, e=0;
3
     while(zahl >= 10000){
4
    zahl -= 10000;
5
    a++;
6
  }
7
  while(zahl >= 1000){
8
    zahl -= 1000;
9
    b++;
10
  }
11
  while(zahl >= 100){
12
    zahl -= 100;
13
    c++;
14
  }
15
  while(zahl >= 10){
16
    zahl -= 10;
17
    d++;
18
  }
19
  while(zahl >= 1){
20
    zahl -= 1;
21
    e++;
22
  }
23
  *puff++ = a + 0x30;
24
  *puff++ = b + 0x30;
25
  *puff++ = c + 0x30;
26
  *puff++ = d + 0x30;
27
  *puff = e + 0x30;
28
}

Aber double braucht man vielleicht 2-3 mal für das ganze Programm. Nur 
dort wo es wirklich notwendig. Zum Beispiel um Frequenzwert auf Zeitwert 
zu dividieren und dann Abweichung in Cent berechnen (1 Cent ist Wurzel 
1200 Grad aus 2 ). Es ist üblich, das verschiedene Temperierungen in 
Cent gegen gleichschwebende Stimmung angegeben werden. Deshalb auch 
Anzeige in Cent ist bequem. Für Centausgabe für LCD reicht float aus.

Frequenzberechnungen für Klavierstimmung müssen sehr genau sein, float 
reicht hier nicht. TLA hat unter anderem eine Mode, wo Obertöne auf 
kritischen Seiten gemessen werden und daraus wird Spreizungskurve für 
bestimmten Klavier berechnet. Ich habe diese Mode ausprobiert: 
Stimmgenauigkeit ist kaum schlechter als bei der Stimmung nach Gehör! 
Gewöhnliche Stimmgeräte erreichen das nie. Also, Genauigkeit... 
Verhältnis 1 Cent heißt 1,00057778950... Für a1 bedeutet das 0,25 Hz 
Schwebung, das ist sehr gut hörbar (da die Obertöne um Mehrfaches öfter 
schweben), es sollte viel genauer gestimmt werden - so ist float hier an 
der Grenze, wenn unter 1 Cent zu gehen ist. Aber auch billige 
Stimmgeräte geben 0,1 Cent Differenzen aus...
Persönliche Seite #5928053
Lesenswert?

Maxim B. schrieb:
>   *puff++ = a + 0x30;
>   *puff++ = b + 0x30;
>   *puff++ = c + 0x30;
>   *puff++ = d + 0x30;
>   *puff = e + 0x30;

Addition von 0x30 ('0') kann man weglassen, wenn man a, b, c, d, e mit 
'0' initialisiert:
1
char a = '0', b = '0', c = '0', d = '0', e = '0';

>   while(zahl >= 10){
>     zahl -= 10;
>     d++;
>   }
>   while(zahl >= 1){
>     zahl -= 1;
>     e++;
>   }

Einfacher:
1
    e += (char) zahl;

> void hex_dec (int zahl, char *puff)

Sollte das nicht "unsigned int zahl" sein (bzw. uint16_t)? Oder es fehlt 
der Fall zahl < 0.

> wenn ich solche double so wie sie sind auf LCD zeigen möchte,
> dann sollte ich selber eine Funktion machen...

Ist hier doch dabei? Als f_to_string() bzw. als f_strtod()

Beitrag "Re: 64 Bit float Emulator in C, IEEE754 compatibel"
#5928063
Lesenswert?

Maxim B. schrieb:
> Ja, wenn ich solche double so wie sie sind auf LCD zeigen möchte, dann
> sollte ich selber eine Funktion machen... Nichts unmögliches. Wenigstens
> habe ich integer bisher auch so ausgegeben.

Ein Floatingpoint-Format funktionert aber anders. Es ist kein Hexenwerk, 
das auszugeben, aber etwas mehr als in dem von dir geposteten Code ist 
es schon.

> Zum Beispiel um Frequenzwert auf Zeitwert zu dividieren und dann
> Abweichung in Cent berechnen (1 Cent ist Wurzel 1200 Grad aus 2 ).

1200 Grad? Der Frequenz-Faktor eines Cent ist die 1200ste Wurzel aus 2. 
Das ergibt also den Faktor der Frequenzen von zwei Tönen, die um einen 
Cent auseinander liegen.
Wenn du wissen willst, um wieviel Cent sich zwei Frequenzen 
unterscheiden, musst du die Frequenzen durcheinander dividieren und dann 
ermitteln, die wievielte Wurzel daraus ein Cent ist. Du brauchst also 
eine Logarithmusfunktion.
Moderator #5928083
Lesenswert?

Maxim B. schrieb:
> Aber double braucht man vielleicht 2-3 mal für das ganze Programm. Nur
> dort wo es wirklich notwendig. Zum Beispiel um Frequenzwert auf Zeitwert
> zu dividieren und dann Abweichung in Cent berechnen

Dazu brauchst du keine 64-Bit-Doubles. 32-Floats sind schon um mehrere 
Größenordnungen genauer als es deine Frequenzmessung je sein wird.

Die relative Auflösung von 32-Bit-Float ist 2**(-23), was 0,0002 Cent 
entspricht. Das sollte doch locker reichen, oder?
Persönliche Seite #5928087
Lesenswert?

Rolf M. schrieb:
> Wenn du wissen willst, um wieviel Cent sich zwei Frequenzen
> unterscheiden, musst du die Frequenzen durcheinander dividieren und dann
> ermitteln, die wievielte Wurzel daraus ein Cent ist. Du brauchst also
> eine Logarithmusfunktion.

Ist das wirklich notwendig?  Bin zwar kein Musiker... aber es geht ja um 
ein Stimmgerät, d.h. die Frequenz ist nicht arg viel anders als die 
Zielfrequenz.  Das Verhältnis der beiden ist also etwa 1 bzw. das 
Verhältnis lässt sich darstellen als 1 + x mit betragsmäßig kleinem x.
1
log_B (1 + x) = ln (1 + x) / ln (B)
2
              = x / ln (B)     für betragsmäßig kleine x.
und wenn die Abweichung 0 ist, dann ist auch x gleich 0 und der Fehler 
der Approximation ist 0.

Wenn es also nicht notwendig ist, den genauen Fehlerwert anzuzeigen, 
dann tut's auch die Näherung; die übrigens gleiches Vorzeichen hat wie 
log_B (1 + x).
#5928092
Lesenswert?

Johann L. schrieb:
> Ist das wirklich notwendig?  Bin zwar kein Musiker...

Ich beschäftige mich zwar etwas mit Musik, würde mich aber nicht als 
Musiker bezeichnen. Aber soweit ich verstehe, ist es notwendig. Es gibt 
in der Musik nicht nur die gleichstufige Stimmung, bei der jeder 
Halbtonschritt genau gleich groß ist. Und nach Maxims obiger Aussage 
werden andere Stimmungen gerne in Cent Abweichung gegenüber einer 
gleichstufigen Stimmung angegeben. Und genau die muss man dann 
erreichen. Das heißt, er muss die Abweichung sehr genau angezeigt 
bekommen, und es reicht nicht, einfach auf 0 zu kommen.
@Maxim: Korrigiere mich, wenn ich hier Blödsinn erzähle.
OP #5928158
Lesenswert?

Rolf M. schrieb:
> @Maxim: Korrigiere mich, wenn ich hier Blödsinn erzähle.

Alles richtig gesagt.

"Historische", oder besser gesagt, nicht gleichschwebende Stimmungen 
hört man am besten in der Musik von Bach und früher. Dann klingt die 
Musik anders. Für Romantik und später reicht gleichschwebende Stimmung.

Hier sind zwei Sachen wichtig:
1. alle historische Stimmungen haben als Grund eine Verbesserung von 
gebräuchlichen Tonarten auf Kosten von weniger gebräuchlichen. Bei 
verschiedenen Stimmungen ist das unterschiedlich erreicht. Ich selber 
mag Stimmungen "Neidhardt kleine Stadt" für Pachelbel und von Valotti 
für Bach.
2. Orgelpfeifen ziehen sich zueinander. Besonders wenn sie nebeneinander 
stehen, was auch bei Terzanordnung von Pfeifen vor allem für große 
Terzen stimmt.

Die großen Terzen von gebräuchlichen Tonarten sind schon wegen der 
Stimmung sauberer, und durch Aneinanderziehen erscheinen sie praktisch 
rein. Schöne reine große Terzen bestimmen Schönheit von Akkorden. Auch 
in Quinten ist Effekt gut hörbar. Die Quinten, die nicht schweben, die 
reinen, die klingen völlig anders.

Bei Klavier ist noch interessanter...
Die Stimmung verwendet man zwar gleichschwebende... Aber die Saiten aus 
Stahl sind hart. Das führt dazu, daß die Obertöne höher werden, als 
theoretischen, und zwar in quadratischer Abhängigkeit von Obertonnummer. 
Da wir aber musikalischen Intervalle dank Obertönen hören, klingt für 
unser Gehör eine reine Oktave zu eng, ebenso Quarten, Quinten und 
Terzen. Je kürzer sind die Saiten, um so hörbarer ist Effekt, deshalb 
ist das für jedes Modell und sogar für jedes Klavier etwas anders. 
Gerade deshalb gibt eine Stimmung nach Gehör bessere Ergebnis, als nach 
Stimmgerät - nur TLA hat hier etwas verbessert.

Die Geräte von diesen Ingenieurbüro kenne ich seit vielen Jahren. Das 
ist eine Sache für Kenner. Die haben auch billigere Modelle, für ein 
paar Hundert Euro, die keine Klavieranalyse machen können. Die 
billigsten können auch keine eigene Stimmungen speichern und können nur 
vom Werk eingestellte Stimmungen verwenden. Richtig gute kosten aber 
über Tausend. Die haben auch eine sehr interessante für Orgel 
Möglichkeit, Tonhöhe nach Raumtemperatur automatisch zu korrigieren - 
das ist aktuell, wenn man z.B. ein Orgelpositiv in einem Saal in der 
Pause stimmt, wo wegen Menschen Raumtemperatur nicht konstant bleibt.

Deshalb die Notwendigkeit, bei Stimmgeräten sehr genau in 
Centbruchteilen hören.
Angehängte Dateien:

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren