3 Stimmen

Warum erhalte ich nur in 1% der Fälle andere Ergebnisse?

Ich versuche, alles nach der hundertsten Dezimalstelle abzuschneiden. (13,4396 wäre 13,43) Sollte das nicht immer oder nie funktionieren?

Ich habe diese Formel, die zu 99 % funktioniert:

    input = (( (double) ((int)(orgInput * 100)) )  / 100) ;

Dann habe ich diese Formelfolge, die arithmetisch äquivalent ist:

    input = (orgInput * 100);
    input = (int) input;
    input = (double) (input);
    input = input / 100;

Diese Eingaben führen nicht zum gewünschten Ergebnis (die Formel schneidet ab und rundet ab, während die aufgeschlüsselten Schritte das gewünschte Ergebnis liefern):

12.33

99.99

22.22

44.32

56.78

11.11

Und ein noch größeres Rätsel ist für mich, warum 33.30 bei keinem von ihnen funktioniert. Unten ist mein Programm, das kontinuierlich läuft, um mein Problem zu demonstrieren.

    #include <stdio.h>
    #include <stdlib.h>

    int main(void)
    {
        double orgInput, input;
        while (4!=3)
        {
            printf("Please enter the dollar amount (up to $100)  => ");
           scanf("%lf", &orgInput);

            /* Truncates anything past hundredths place */
            input = (orgInput * 100) ;
            printf("\n1. input is %g \n ", input);

            input = (int) input ;
            printf("\n2. input is %g \n ", input);

            input = (double) (input)   ;
            printf("\n3. input is %g \n", input);

            input = input / 100 ;
            printf("\n4. input is %.2lf \n", input);

            input = (( (double) ((int)(orgInput * 100)) )  / 100) ;
            printf("\nUsing the formula the input is %.2lf \n \n\n", input);

        }
        system("PAUSE");
        return 0;
    }

Vielen Dank im Voraus!!!! P.S. Entschuldigung für die Formatierung, ich bin noch dabei, mich an Stackoverflow zu gewöhnen

Schlüsselbegriffe: Umwandlung von Double in int Präzisionsfehler

5voto

paddy Punkte 59105

Ich glaube, Sie leiden unter Fließkomma-Präzisionsfehlern.

Sie sollten in der Lage sein, dies zu beheben:

const double epsilon = 1e-10;  // Or some suitable small number
input = floor(orgInput * 100 + epsilon) / 100;

Eine Alternative besteht darin, dies bei der Eingabe zu verhindern. Anstatt einen Double einzulesen, liest man einen String und analysiert diesen, um den Dollar- und Cent-Betrag herauszubekommen (wobei Cent genau 2 Stellen nach dem Dezimalpunkt sind, falls vorhanden). Alles andere können Sie dann ignorieren.

Wenn Sie mit Geld arbeiten, das auf Cents abgeschnitten ist, ist es im Allgemeinen am besten, wenn Sie es in Cents behalten und ganze Zahlen verwenden. Entweder das oder Sie runden ab, anstatt abzuschneiden (für mein obiges Beispiel würde das ein Epsilon von 0,5 bedeuten).

3voto

Myforwik Punkte 3208

Sie müssen wissen, dass Gleitkommazahlen im Binärformat wie folgt dargestellt werden:

2^(Exponent) * Mantisse

Der Exponent ist eine Standard-Ganzzahl, aber die Mantisse (ein Wert zwischen 1 und 2) ist eine Anzahl von Bits, wobei jedes Bit einen Bruch darstellt: 1, 1/2, 1/4, 1/8, 1/16 und so weiter... Daher ist es nicht möglich, dass die Mantisse bestimmte Werte exakt wiedergibt, sie hat eine Genauigkeit von +/- einem Bruchteil.

Sie haben zum Beispiel 33,30 erwähnt. Als Float kann 33,30 nur sein: 2^5 * Mantisse.

In diesem Fall muss die Mantisse genau 33,30/32 = 1,40625 betragen. Aber durch die Bildung aus den Brüchen kommt man dem Wert am nächsten: 1,0406249999999999111821580299874767661094. Der tatsächliche Wert des Double ist also nicht 33,30, sondern 33,29999999999971578290569595992565155029296875, was natürlich auf 33,29 abgerundet wird, wenn man den Typ in Integer umwandelt.

Der richtige Weg, Ihr Programm zu reparieren, besteht darin, gar nicht erst einen Schwimmer einzulesen. Sie sollten zwei durch Dezimalzahlen getrennte Ganzzahlen einlesen, und wenn scanf einen Wert zurückgibt, der anzeigt, dass nicht zwei Ganzzahlen eingelesen wurden, dann scannen Sie es als eine Ganzzahl für den Fall, dass es sich nur um einen Dollar-Wert handelt.

Leider arbeitet printf mit Konvertierungen in Ints und gibt keine doppelt genauen Fließkommazahlen mit mehr als 6 Nachkommastellen aus, weshalb Sie den Wert 33,30 sehen, obwohl Sie printf bitten, den Wert eines Double zu drucken.

1voto

Alexey Frunze Punkte 59460

Die meisten Rechner verwenden binäre, nicht dezimale Gleitkommazahlen. Während die Umwandlung von Binär- in Dezimalzahlen (theoretisch) immer exakte Werte ergibt, ist es unmöglich, von Dezimal- in Binärzahlen zu konvertieren, ohne zu runden (ich denke dabei nicht an den unpraktischen Fall, dass Zahlen eine unendliche Anzahl von Stellen haben können).

Daher werden alle binären Fließkommazahlen etwas von dem abweichen, was sie im Dezimalsystem gewesen wären.

Die einzigen 1-stelligen Dezimalbrüche, die binär dargestellt werden können, sind: .0, .5.

Ebenso sind zweistellige Dezimalbrüche exakt in Binärzahlen darstellbar: .00, .25, .50, .75 (siehe aquí ).

Wenn Sie wollen, was ich bezweifle, können Sie auf den nächsten Bruchteil der Vier aufrunden.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X