NSScanner macht Phantasiewerte

  • NSScanner macht Phantasiewerte

    Hi,

    Hintergrund: In ein Textfeld wird eine Zahl mit 2 Nachkommastellen eingegeben und daraus soll eine Double Zahl werden.
    Problem dabei: Eingabe 40,01 => 40.01 also Komma muss in Punkt geändert werden.

    Kann mir jemand bitte das folgende Phänomen erklären ?

    Das ist meine Routine:

    Quellcode

    1. +(double) ConvertStringToDouble:(NSString *)numberString {
    2. NSScanner *scanner;
    3. NSLocale *local =[NSLocale currentLocale ];
    4. [scanner setLocale:local];
    5. float result;
    6. scanner = [NSScanner localizedScannerWithString:numberString];
    7. [scanner scanFloat:&result];
    8. return (double)result;
    9. }


    Eingabe : numberString = @"40,01"
    Ausgabe: result: 40.009998

    Eingabe: numberString = @"94,02"
    Ausgabe: result: 94.019997

    Eingabe: numberString = @"94.01" (also mit Punkt)
    Ausgabe: result: 94.00000
    Es gibt zwei Dinge, die sind unendlich. Das Universum und die menschliche Dummheit. Wobei beim Universum bin ich mir nicht sicher - Albert Einstein
  • Ich hab eine andere Lösung gefunden, die aber angeblich nicht immer funktioniert:

    Quellcode

    1. NSString *newString = [numbrtString stringByReplacingOccurrencesOfString:@"," withString:@"."];
    2. double result = [newString doubleValue];


    Da wird zwar aus 92,04 92,04000, was aber ok ist.
    Es gibt zwei Dinge, die sind unendlich. Das Universum und die menschliche Dummheit. Wobei beim Universum bin ich mir nicht sicher - Albert Einstein
  • Floats und Doubles können Zahlen mit Nachkommastellen in der Regel nur annähern. Beispielsweise hat 0,02 eine periodische Binärdarstellung. Dadurch kommen solche ungenauen Werte zustande. Dabei sind Floats aufgrund der geringeren Bitzahl noch ungenauer als Doubles. Deine Lösung ist keine, da die Genauigkeit natürlich nicht von dem Trennzeichen für die Nachkommastellen abhängt.

    Die Klasse bietet mit scanDouble: auch eine Möglichkeit, Doubles direkt einzulesen. Damit solltest du die gleiche Genauigkeit, wie im 2. Listing erhalten. Ansonsten solltest du den ursprünglichen Weg bevorzugen, da er wesentlich sauberer ist.
    „Meine Komplikation hatte eine Komplikation.“
  • Die etwas falschen Nachkommawerte (Beispiele 1 und 2) sind Rundungsfehler der Floats. Bei Beispiel 3 hört der Scanner bei dem Punkt mit dem Parsen auf, da der in der current Locale nicht mehr zur Zahl gehört.

    Rundungsfehler sind schwierig ganz zu vermeiden, du kannst entweder auf double oder gleich auf NSDecimalNumber gehen. Ich würde den String mit dem passenden Konstruktor in eine NSDecimalNumber konvertieren und anschließend über einen NSNumberFormatter wieder in einen String. Man kann das natürlich auch mit Textersetzungsfunktionen machen, damit kommt man aber in Teufels Küche, wenn falsche oder eigenartig formatierte Zahlen reinkommen. Z.B. werden Punkt und Komma je nach Locale sowohl als Dezimal- als auch als Tausenderseparator verwendet.
    Multigrad - 360°-Produktfotografie für den Mac