Funktion ftoa - Rundungsproblem


  • Mod

    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?


  • Mod

    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.

    http://openbook.galileocomputing.de/c_von_a_bis_z/005_c_basisdatentypen_008.htm#mja222ddceb198f6a4f04180cc890135b6



  • 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.


Anmelden zum Antworten