Falsche Ergebnisse beim (int)-Typecast?



  • Moin,
    nachdem ich gerade fast wahnsinnig geworden bin, als eine Funktion ständig falsche Ergebnisse brachte, konnte ich den Fehler lokalisieren, werde aber kein bisschen schlau daraus.
    Als beispiel dient der Ausdruck (log(8.0) / log(2.0)), bekanntermaßen genau 3.

    printf("%f", (log(8.0) / log(2.0)));       //liefert korreke 3.0000000
    printf("%d", (int)(log(8.0) / log(2.0)));  //das hier jedoch "2"
    

    Schreibe ich aber

    printf("%d", (int)(float)(log(8.0) / log(2.0))); //...kommt korrekt "3" heraus,
    printf("%d", (int)(double)(log(8.0) / log(2.0)));//nicht jedoch hier: "2"
    
    double x = (log(8.0) / log(2.0));
    printf("%d", (int)x);           //hier wieder korrekt 3
    

    Aber es kommt noch besser:

    printf("%d", (int)(log(16.0) / log(2.0)));  //Plötzlich die richtige 4?!?
    

    In einer Schleife Ergeben sich diese Ergebnisse:

    (int)1.000000  -> 1
    (int)2.000000  -> 2
    (int)3.000000  -> 2   FALSCH
    (int)4.000000  -> 4
    (int)5.000000  -> 5
    (int)6.000000  -> 5   FALSCH
    (int)7.000000  -> 6   FALSCH
    (int)8.000000  -> 8
    (int)9.000000  -> 9
    (int)10.000000  -> 10
    (int)11.000000  -> 11
    (int)12.000000  -> 11   FALSCH
    (int)13.000000  -> 12   FALSCH
    (int)14.000000  -> 13   FALSCH
    (int)15.000000  -> 14   FALSCH
    (int)16.000000  -> 16
    (int)17.000000  -> 17
    (int)18.000000  -> 18
    (int)19.000000  -> 19
    

    Ich seh da absolut keinen Sinn drin. Wäre schön wenn mir das jemand erklären kann.. 😕



  • Das Problem ist die Art, mit der der Compiler auf ganze Zahlen rundet.
    Nämlich immer runter. (Wegschneiden des Nachkommateils).

    (int)2.9999999 das sind 2.

    (log(8.0) / log(2.0))) sind minimal weniger als 3. (begrenzte Rechengenauigkeit)
    Also als int gecastet 2.

    (int)(float)(log(8.0) / log(2.0)));
    

    Hier wird erst nach float berechnet. Da auch float nur begrenzte Genauigkeit hat, wird auf 3.~ gerundet.
    Nun ergibt das Abschneiden mit int immernoch 3.



  • Ja, dass bei dem Typecast immer abgerundet wird wusste ich, aber normalerweise wird doch immer, ob Taschenrechner oder Google: log(8) / log(2), so mit der Ungenauigkeit umgegangen, dass trotzdem das richtige Ergebnis herauskommt, nämlich genau 3 und keine Periode und auch nichts darunter.

    Also arbeitet der Compiler(oder math.h oder was auch immer hier verantwortlich ist) in der hinsicht doch wohl recht unbefriedigend ?



  • Die meisten Taschenrechner, und google wohl auch, rechnen nicht mit nur 4 Byte großen floats.



  • SeppSchrot schrieb:

    Die meisten Taschenrechner, und google wohl auch, rechnen nicht mit nur 4 Byte großen floats.

    genau das ist es: die C Datentypen sind nicht wirklich genau. Sie brauchen ja auch kaum platz.

    Wenn du viel wert auf genauigkeit legst, empfehle ich gmp.

    Ansonsten: meistens reicht es immer zu runden um die meisten fehler rauszubekommen. ich mache es meistens so: ich rechne auf 2 dezimalstellen mehr, als ich brauche und runde dann jedesmal, so habe ich eine gewisse sicherheit vor rundungsfehlern.


Anmelden zum Antworten