Frage

Dieser Code funktioniert (C # 3)

double d;
if(d == (double)(int)d) ...;
  1. Gibt es einen besseren Weg, dies zu tun?
  2. Für Fremd Gründe, warum ich so die doppelte Besetzung vermeiden wollen; was schön Wege existieren, anders als das? (Auch wenn sie nicht so gut sind)

Hinweis: Mehrere Leute darauf hingewiesen, die (wichtig) hinweisen, dass == ist oft problematisch Neueinstufung Gleitkomma. In diesen Fällen erwarte ich, dass Werte im Bereich von 0 bis einigen hundert und sie sollen ganze Zahlen sein (nicht Ints sind Fehler) dann, wenn diese Punkte „sollte nicht“ ein Problem für mich sein.

War es hilfreich?

Lösung

d == Math.Floor(d)

macht das Gleiche mit anderen Worten.

Hinweis: Hoffentlich sind Sie sich bewusst, dass Sie sehr vorsichtig sein, wenn diese Art der Sache zu tun; Schwimmer / Doppel akkumuliert sehr leicht miniscule Fehler, die genauen Vergleiche machen (wie diese) ohne ersichtlichen Grund versagen.

Andere Tipps

Wenn Ihr Doppel das Ergebnis einer anderen Berechnung ist, werden Sie wahrscheinlich wollen so etwas wie:

d == Math.Floor(d + 0.00001);

Auf diese Weise, wenn es eine geringfügige Rundungsfehler gewesen ist, es wird immer noch übereinstimmen.

Das würde funktionieren denke ich:

if (d % 1 == 0) {
  //...
}

Ich kann die C # -spezifische Teil der Frage beantworten, aber ich muss Sie wahrscheinlich darauf hinweisen, sind ein allgemeines Problem mit Gleitkommazahlen fehlt.

Im Allgemeinen wird integerness nicht gut auf Schwimmern definiert. Aus dem gleichen Grund ist, dass die Gleichstellung nicht gut auf Schwimmern definiert. Gleitkomma-Berechnungen umfassen normalerweise sowohl Rundung und Darstellungsfehler.

Zum Beispiel 1.1 + 0.6 != 1.7.

Yup, das ist nur die Art und Weise der Arbeit Gleitkommazahlen.

Hier 1.1 + 0.6 - 1.7 == 2.2204460492503131e-16.

Genau genommen ist die nächste Sache, Gleichheit Vergleich Sie mit Schwimmern tun können, ist zu vergleichen sie bis zu einer ausgewählten Genauigkeit .

Wenn dies nicht ausreicht, müssen Sie mit einer Dezimalzahl Darstellung arbeiten, mit einer Gleitkommazahl Darstellung mit eingebautem Fehlerbereich oder mit symbolischen Berechnungen.

Wenn Sie nur gehen, um es zu konvertieren, Mike F / Khoth Antwort ist gut, aber nicht ganz Ihre Frage beantworten. Wenn Sie tatsächlich testen wollen, und es ist wirklich wichtig, empfehle ich Ihnen etwas implementieren, die eine Fehlermarge enthält.

Zum Beispiel, wenn Sie erwägen, Geld und Sie wollen auch Dollar-Beträge testen, könnte man sagen (nach Khoth des Muster):

if( Math.abs(d - Math.Floor(d + 0.001)) < 0.001)

Mit anderen Worten, nehmen Sie den absoluten Wert der Differenz des Wertes und es ist Integer-Darstellung und sicherzustellen, dass es klein ist.

Sie brauchen nicht die zusätzliche (double) drin. Dies funktioniert:

if (d == (int)d) {
 //...
}

Mit Math.Truncate ()

Ein einfacher Test, wie etwa 'x == floor (x)' gewährleistet ist mathematisch korrekt zu arbeiten, für jede feste Präzision FP-Nummer.

Für alle Rechtsfest Präzision FP-Codierungen repräsentieren verschiedene reelle Zahlen, und so für jede ganze Zahl x gibt es höchstens eine Fest Präzision FP-Codierung, die es genau übereinstimmt.

Daher ist für jede ganze Zahl x, die in einer solchen Art und Weise dargestellt werden können, haben wir x == Boden (x) notwendig, da Boden (x) per Definition gibt den größten FP-Zahl y, so daß y <= x und y eine ganze Zahl ist; so Boden (x) muss x zurück.

So können Sie wählen, welche Präzision Sie suchen, plus oder minus einem halben Tick, für Floating-Point-Drift zu berücksichtigen. Der Vergleich ist ein integraler Bestandteil auch das ist schön.

static void Main(string[] args)
{
    const int precision = 10000;

    foreach (var d in new[] { 2, 2.9, 2.001, 1.999, 1.99999999, 2.00000001 })
    {
        if ((int) (d*precision + .5)%precision == 0)
        {
            Console.WriteLine("{0} is an int", d);
        }
    }
}

und die Ausgabe ist

2 is an int
1.99999999 is an int
2.00000001 is an int

So etwas

double d = 4.0;
int i = 4;

bool equal = d.CompareTo(i) == 0; // true

Könnten Sie verwenden diese

    bool IsInt(double x)
    {
        try
        {
            int y = Int16.Parse(x.ToString());
            return true;
        }
        catch 
        {
            return false;
        }
    }

Um die Genauigkeit des Doppelgriffes ...

Math.Abs(d - Math.Floor(d)) <= double.Epsilon

Sie sich den folgenden Fall, in dem ein Wert weniger als double.Epsilon als Null vergleichen ausfällt.

// number of possible rounds
const int rounds = 1;

// precision causes rounding up to double.Epsilon
double d = double.Epsilon*.75;

// due to the rounding this comparison fails
Console.WriteLine(d == Math.Floor(d));

// this comparison succeeds by accounting for the rounding
Console.WriteLine(Math.Abs(d - Math.Floor(d)) <= rounds*double.Epsilon);

// The difference is double.Epsilon, 4.940656458412465E-324
Console.WriteLine(Math.Abs(d - Math.Floor(d)).ToString("E15"));
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top