Aufrundungsproblem

  • Aufrundungsproblem

    Hallo Experten,

    seit Stunden suche ich eine 'einfache' Lösung für das folgende Problem:

    NSLog(@"%.2f", 2.325);
    NSLog(@"%.2f", 362.325);

    Ich erwarte in beiden Fällen eine Aufrundung, also folgende Ausgabe:

    2.33
    362.33

    Aber das Ergebnis ist:

    2.33
    362.32

    warum, warum, warum???? Wo ist der Unterschied?

    Vielen Dank
    Coding is poetry. Cocoa the inspiration (Meine Posts bitte nicht mit IE betrachten. Ich tue das auch nicht.)
  • RE: Aufrundungsproblem

    Original von coconut
    Hallo Experten,

    seit Stunden suche ich eine 'einfache' Lösung für das folgende Problem:

    NSLog(@"%.2f", 2.325);
    NSLog(@"%.2f", 362.325);

    Ich erwarte in beiden Fällen eine Aufrundung, also folgende Ausgabe:

    2.33
    362.33

    Aber das Ergebnis ist:

    2.33
    362.32

    warum, warum, warum???? Wo ist der Unterschied?

    Vielen Dank

    Das liegt vermutlich daran, daß 0.325 in Binärdarstellung ein unendlich langer Bruch ist. Es müßte wenn ich mich nicht verrechnet habe sein

    Quellcode

    1. 0.0100100110011001100110011 usw.
    Wenn Du das als float speicherst, muß es nun irgendwo abgeschnitten werden - ein float hat nur 24 bit für die Mantisse. Und jenachdem was vor dem Komma steht (2 oder 362), passiert das anscheinend an anderen Stellen. Daher ist 362.325 eigentlich als 362.3249995 oder so ähnlich gespeichert. Das bedeutet, daß das System dann beim Runden gerade noch nicht aufrundet. Drucke mal mit %.10f und vergleiche. Oder wandle erst mal in (double).

    Lösung => addiere einen ganz kleinen Wert, also bei %.2f z.B. 0.001.

    -- hns
  • RE: Aufrundungsproblem

    vermutlich weil zu dem oben noch die standard strategie folgende ist

    Round to the closest possible return value; when halfway between two possibilities, return the possibility whose last digit is even.

    In practice, this means that, over the long run, numbers will be rounded up as often as they are rounded down; there will be no systematic bias.


    das beste ist du schaust dir mal man roundf an oder schreibst dir eine eigenen methode - bzw wenn du genaue grundlagen brauchst benutzt du die Klasse NSDecimalNumber
    snafu
    :() { :|: &};:
    sometimes i dream in hex
    Obey gravity! Because its a law!
  • Wenn du zu ner Gleitkommazahl 0.5 addierst und dann die Nachkommastellen abschneidest, erhälst du immer eine korrekt gerundete ganze Zahl. Bei negativen Werten wird 0.5 abgezogen. Nun musst du nur noch die Kommastelle verschieben.

    Quellcode

    1. double Round(double Zahl, unsigned int Stellen)
    2. {
    3. Zahl *= pow(10, Stellen);
    4. if (Zahl >= 0)
    5. floor(Zahl + 0.5)
    6. else
    7. ceil(Zahl - 0.5);
    8. Zahl /= pow(10, Stellen);
    9. return Zahl;
    10. }
    Seminare, Artikel, Code. ObjectiveCeeds - alles für die Apfelzucht.
  • vielen Dank für die antworten.

    die angegebene Round Funktion hat das selbe Ergebnis gegeben.

    Aber wenn ich ich folgendes schreibe funktioniert es

    NSLog(@"%.2f", 2.325);
    NSLog(@"%.2f", (float)362.325);


    Kann ich davon ausgehen, dass es mit floats immer funktioniert?


    EDIT: Das funktioniert auch

    NSLog(@"%.2f", 2.325);
    NSLog(@"%.2f", 362.325 + 0.00001);
    Coding is poetry. Cocoa the inspiration (Meine Posts bitte nicht mit IE betrachten. Ich tue das auch nicht.)
  • Quellcode

    1. Kann ich davon ausgehen, dass es mit floats immer funktioniert?


    Ich gehe grundsätzlich davon aus, das mit floats garnichts funktioniert, macht weniger Arbeit ;)

    Ohne Scheiß, ob Cell Prozessor oder Taschenrechner, mit der Genauigkeit von Fließkommazahlen ist das immer so ne Sache. Du hast immer nen Fehler von x Digit mit dem du rechnen musst (D.h. kann passieren, muß aber nicht). Daher ist der Trick auf int auszuweichen immer ganz brauchbar.
    Seminare, Artikel, Code. ObjectiveCeeds - alles für die Apfelzucht.
  • Also ich weiss nicht. Mit float funktioniert bei mir mehr als mit double.

    Quellcode

    1. - (double)total
    2. {
    3. double test = 8.61;
    4. return test;
    5. }



    diese Funktion wird von eine Tabellenspalte durch binding aufgerufen. Und in der Spalte steht dann 8.6099999999999.

    Aber siehe da

    Quellcode

    1. - (float)total
    2. {
    3. float test = 8.61;
    4. return test;
    5. }


    funktioniert wie gewünscht. (Ich habe hier bewusst die NSNumberFormatter weggelassen)


    Und für Aufrundungen benutze ich folgendes.

    Quellcode

    1. [[NSString stringWithFormat:@"%.2f", floatWert + 0.00001] floatValue]


    ich weiss aber nicht ob es wirklich richtig ist.
    Um int zu verwenden ist es bei mir leider zu spät. Die Werte kommen von CoreData ManagedObjects.
    Coding is poetry. Cocoa the inspiration (Meine Posts bitte nicht mit IE betrachten. Ich tue das auch nicht.)
  • Ja, er wird das früher oder später tun. Lies mal, was ich verlinkt habe
    cocoading
    Wenn es etwa um den Stand Ihres Kontos geht, würden Sie aber komisch schauen, wenn ein Cent fehlen würde. Nicht wegen des Cents, sondern weil sie mutmaßlich jegliches Vertrauen in Ihre Bank verlören. Daher rechnen auch Banken die Kontensaldi nicht mit Fließkommazahlen sondern mit den oben erwähnten Ints: In ganzzahligen Cents. Ein Kontostand von 354,35 wird also gar nicht von Fließkommazahlen dargestellt, sondern vielmehr als 35.435 Cents. Und das ist gut so!
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Vielen dank! Das bringt für mich noch andere Fragen mit sich. Wenn ich jetzt alles in Cents speichern würde, muss ich ja immer noch eine Dezimalzahl anzeigen und auch eine Dezimalzahl einlesen.

    Kurzgefasst, hier meine Bindingfunktionen:

    Quellcode

    1. - (void)setPrice:(float)aPrice
    2. {
    3. // ...???
    4. }
    5. - (float)price
    6. {
    7. // ... ???
    8. }


    oder ist hier schon float falsch. Wenn ja, was muss man tun? Eigene ValueTransformer schreiben? Muss man nicht irgendwann durch 100 dividieren um Cent in Euro darstellen zu können?

    Ich hoffe ich konnte es rüberbringen und ich hoffe nichts überlesen zu haben :)
    Coding is poetry. Cocoa the inspiration (Meine Posts bitte nicht mit IE betrachten. Ich tue das auch nicht.)
  • Vielen Dank für die ganzen Hilfen!
    Ich glaube es war nicht gut in CoreData-Modeller Double als Entity-Attribute-Typ auszuwählen. Nun muss ich wohl Decimal verwenden.
    Coding is poetry. Cocoa the inspiration (Meine Posts bitte nicht mit IE betrachten. Ich tue das auch nicht.)
  • Aja, vielen Dank! Das hätte ich mir schon fast gedacht.

    Obwohl ich jetzt NSDecimalNumber verwenden möchte, bin ich schon neugierig ob solche ValueTransformers schon existieren, da es ja ein wichtiges Thema ist?
    Coding is poetry. Cocoa the inspiration (Meine Posts bitte nicht mit IE betrachten. Ich tue das auch nicht.)
  • "Divide"By100. Also heisst das ungefähr so etwas:

    Quellcode

    1. valueInCents/100.0


    Hat man dann nicht wieder eine Fließkommazahl? Oder ist das dann nicht mehr relevant? Aber man übergibt dann doch wieder eine Fließkommazahl an die View, oder bin ich jetzt total daneben?
    Coding is poetry. Cocoa the inspiration (Meine Posts bitte nicht mit IE betrachten. Ich tue das auch nicht.)
  • Du kannst ja auch einen String zurückgeben, wenn du willst. Der Punkt ist aber, dass du an dieser Stelle anständig runden, "halbe Werte" aufaddieren kannst usw. Das solltest du mit den im Model gespeicherten Werten nicht tun, da du dich sonst bei der Saldenbildung ziemlich schnell über die Ergebnisse wunderst. Mit anderen Worten: In diesem Falle beleibt dein Model sauber.
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Ja String ist eine gute Idee.

    Zunächst habe ich mal NSDecimalNumber ausprobiert und ich finde das Klasse!
    Man kann ja auch immer noch in der View direkt NSNumberFormatter verwenden. Also die Umstellung war für mich nicht viel Aufwand gewesen.

    Aber ich habe unglücklicherweise nicht viel über die Verwendung von NSDecimalNumber gefunden (google, etc). Nur dass man "niemals" float sondern, wie Tom9811 schon geschrieben hat, entweder in Cents oder NSDecimalNumber verwenden soll.

    Meine Frage: Muss man immer mit den Methoden [decNum decimalNumberBy...] arbeiten? Wenn ich zum Beispiel einen Betrag mit 1.5 multiplizieren möchte, muss ich dann 1.5 auch als NSDecimalNumber definieren?

    Vielen Dank
    Coding is poetry. Cocoa the inspiration (Meine Posts bitte nicht mit IE betrachten. Ich tue das auch nicht.)