Funktion ftoa - Rundungsproblem
-
Zur Umwandlung eines float-Wertes in einen char-String verwenden wir diese Funktion:
void ftoa(float f, char* buffer) { char tmp[32]; int32_t index = (sizeof(tmp) - 1); if (f < 0.0) { *buffer = '-'; ++buffer; f = -f; } int32_t i = f; while (i > 0) { tmp[index] = ('0' + (i % 10)); i /= 10; --index; } memcpy((void*)buffer, (void*)&tmp[index + 1], ((sizeof(tmp) - 1) - index)); buffer += ((sizeof(tmp) - 1) - index); *buffer = '.'; ++buffer; *buffer++ = ((uint32_t)(f * 10.0) % 10) + '0'; *buffer++ = ((uint32_t)(f * 100.0) % 10) + '0'; *buffer++ = ((uint32_t)(f * 1000.0) % 10) + '0'; *buffer++ = ((uint32_t)(f * 10000.0) % 10) + '0'; *buffer++ = ((uint32_t)(f * 100000.0) % 10) + '0'; *buffer++ = ((uint32_t)(f * 1000000.0) % 10) + '0'; *buffer = '\0'; }
Allerdings gibt es dabei beim Ausdruck mit printf Rundungsprobleme:
PrettyOS [Version 0.0.0.361] Console 2: HELLO .ELF -------------------------------------------------------------------------------- Berechnung quadratischer Gleichungen vom Typ x*x + p*x + q = 0 Bitte p eingeben: 12345 p= 12345.000008 Bitte q eingeben: 123456 q= 123456.000082 x1 = -10.008600 x2 = -12334.991218 Press key.
Das verwendete User-Programm:
#include "userlib.h" int main() { setScrollField(0, 43); // We do not want to see scrolling output... puts("Berechnung quadratischer Gleichungen vom Typ x*x + p*x + q = 0"); float p, q, x1, x2; printf("\nBitte p eingeben: "); char str[80]; gets(str); p = atof(str); printf("\np= %f\n",p); printf("Bitte q eingeben: "); gets(str); q = atof(str); printf("\nq= %f\n",q); x1 = -p/2 + sqrt( p*p/4.0 - q ); x2 = -p/2 - sqrt( p*p/4.0 - q ); printf("x1 = %f x2 = %f\n\n", x1, x2); printf("Press key."); if (getch()); return 0; }
Wie können wir dies verbessern?
-
Erhard Henkes schrieb:
Wie können wir dies verbessern?
Liegt denn der Fehler außerhalb des zu erwartenden Rahmens?
-
Eine Fließkommazahl mit 6-stelliger Genauigkeit wie float kann sechs Dezimalstellen nicht immer korrekt unterscheiden. Wenn beispielsweise die Zahl vor dem Komma (z. B. »1234,1234«) bereits vier Stellen besitzt, so kann sie nach dem Komma nur noch zwei Stellen unterscheiden. Somit wären die Gleitpunktzahlen 1234,12345 und 1234,123999 als float-Zahlen für den Computer nicht voneinander zu unterscheiden. Mit 6-stelliger Genauigkeit sind die signifikanten Stellen von links nach rechts gemeint. Der Typ float ist also ungeeignet für kaufmännische und genaue wissenschaftliche Berechnungen.
-
Ich hatte im IRC ja schon geschrieben gehabt, dass man floats nicht mit höherer Genauigkeit ausgeben kann als sie im Speicher liegen. Um "schönere" Ausgaben zu kriegen kann man natürlich nach 6 Stellen abschneiden oder runden. Dabei dürfte allerdings im Allgemeinen die Abweichung ansteigen. Und wenn man mit den Zahlen weiterrechnen will, dann interessiert einen meistens die genaue Zahl im Speicher und keine gerundeter Wert.