Prozentrechnung mit int64?



  • Ich verwende bislang double Werte für Finanzberechnungen.
    Es immer etwas tricky, an der richtigen Stelle mit der richtigen Anzahl von Dezimalstellen zu runden.
    Ich lese immer wieder von Leuten, dass die Verwendung von double für Geldbeträge "kriminell" sei, aber ich möchte nun auch mal professionelle Alternativen sehen.

    Ich habe bestimmt 10 Jahre diverse Varianten probiert und für das Runden von double Werten die folgende Funktion als sehr gut befunden:

    double CPRoundDouble(double dValue, int iDecimalCount)
    {
        double dKeep = 0.0;
        double dRound = 0.0;
        double dMul = 0.0;
        if(iDecimalCount < -10 || iDecimalCount > 19)
            return dValue;
        dMul = pow(10.0, (double) iDecimalCount);
        dRound = modf((dValue*dMul), &dKeep);
        if(dRound >= 0.50)
            dKeep += 1.0;
        return dKeep/dMul;
    }
    

    Dasselbe habe ich für int64 Werte wie folgt gebaut. Der Wert ival stellt eine Dezimalzahl so dar, dass 87654.1264 als 876541264 geschrieben werden, also mit
    10000 multipliziert. CPMoneyRound(876541264,4,2) gibt dann 876541300 zurück:

    const int64 POT64[] = {
    /* 0: */ 1,
    /* 1: */ 10,
    /* 2: */ 100,
    /* 3: */ 1000,
    /* 4: */ 10000,
    /* 5: */ 100000,
    /* 6: */ 1000000,
    /* 7: */ 10000000,
    /* 8: */ 100000000,
    /* 9: */ 1000000000,
    /* 10: */ 10000000000,
    /* 11: */ 100000000000,
    /* 12: */ 1000000000000,
    /* 13: */ 10000000000000,
    /* 14: */ 100000000000000,
    /* 15: */ 1000000000000000,
    /* 16: */ 10000000000000000,
    /* 17: */ 100000000000000000,
    /* 18: */ 1000000000000000000
    };
    #define potenz64(e) POT64[e]
    
    int64 CPMoneyRound(int64 ival, int moneydecimals, int destination_decimalcount)
    {
        int64   fakt;
        int64   res;
        if(destination_decimalcount < 0 || destination_decimalcount > 8)
        {
            return ival;
        }
        if(moneydecimals < destination_decimalcount)
            return ival;
        fakt = potenz64(moneydecimals - destination_decimalcount);
        if(ival > 0)
            res = ((ival + (fakt / 2)) / fakt) * fakt;
        else
            res = ((ival - (fakt / 2)) / fakt) * fakt;
        return res;
    }
    

    Nun bin ich aber kein Mathematiker und habe keine Ahnung, wie man etwas kompliziertere Dinge mit int64 bauen könnte. Ich habe da z.B. eine Funktion, die die Mehrwertsteuer berechnet, die in einem Bruttobetrag enthalten ist. Mit double sieht die so aus:

    double CPGetIncludedTaxDC(double Betrag, double Prozent, int decimalcount)
    {
        return CPRoundDouble( (1 / ((100.0 + Prozent) / Prozent)) * Betrag, decimalcount);
    }
    

    Wie kann man das ganz konkret mit int64 umsetzen? Kann mir da einer helfen?



  • mareb schrieb:

    Wie kann man das ganz konkret mit int64 umsetzen? Kann mir da einer helfen?

    Erst multiplizieren, dann dividieren.

    Edit: Hab nachgeschlagen und weiss jetzt, wie man multiplizieren schreibt.



  • mngbd schrieb:

    Erst multiplizieren, dann dividieren.

    Edit: Hab nachgeschlagen und weiss jetzt, wie man multiplizieren schreibt.

    Hallo,
    danke und sorry: wenn ich wüßte, wie ich die Formel dazu umstellen müßte, würde ich das jetzt hier hinschreiben.

    Grüße



  • Das Thema ´Fliesskomma kriminell für Geldbeträge´ gab es hier und in anderen Rubriken in diesem Forum schon mehrfach. Der eine sagt: ´du bist bescheuert, das macht man nicht´ und der andere macht es einfach manchmal mit den gewünschten zuverlässigen Ergebnissen. Prozentrechungen haben nun einmal Nachkommastellen. Irgendwie muss man das handeln. Integer-Typen können das nicht regeln oder man braucht spezielle Datentypen und Funktionen dafür.



  • Also ich hoffe mal ich übersehe hier jetzt nichts essenzielles, aber ich poste das trotzdem einfach mal..

    #define uint64 unsigned __int64
    
    uint64 vatax(uint64 amount, int vatax)
    {
      return (amount * vatax) / 100;
    }
    

    Wenn man jetzt mit dem 100k fachen eines cents rechnet und am ende halt vor dem anzeigen rundet, sollte das ganze mehr oder weniger genau sein..

    Man kann im übrigen ca
    1844674407370.95.51616 €
    so darstellen, das sollte auch für gut betuchte Leute reichen 😃



  • cooky451 schrieb:

    Also ich hoffe mal ich übersehe hier jetzt nichts essenzielles, aber ich poste das trotzdem einfach mal..

    #define uint64 unsigned __int64
    
    uint64 vatax(uint64 amount, int vatax)
    {
      return (amount * vatax) / 100;
    }
    

    Mit dieser Berechnung erhälts Du die Mehrwertsteuer eines Betrages, also von 100,00 Euro dann 19 Euro, wenn vatax = 19 ist.
    Vielleicht war ich an der Stelle nicht deutlich genug, ich möchte vom Brutto-Betrag 100,00 den Netto-Betrag abziehen und die enthaltene Mehrwertsteuer berechnen. Bei 19% sind das 15,9664 Euro.

    Ich möchte gerne wissen, wie diejenigen, die double-Werte bei Geldbeträgen 'kriminell' (oder sonstwie verkehrt) halten, das berechnen.

    Und von den anderen, die das nicht kriminell finden, lasse ich mir auch gerne sagen, dass es ohne Fließkommazahlen nicht geht - oder nur mit großem Aufwand geht. Wie gesagt, ich bin kein Mathematiker, sonst würde ich bestimmt die GMP-Library http://gmplib.org/ verstehen und für diesen Zweck eine Lösung finden.

    Bei C-Sharp gibt es den Datentyp Currency mit 128 Bit, auf den ich etwas neidisch bin. Nun brauche ich keine 128 Bit für kaufmännische Software, oder? Aber die Genauigkeit der Berechnungen hätte ich gerne.



  • mareb schrieb:

    Vielleicht war ich an der Stelle nicht deutlich genug, ich möchte vom Brutto-Betrag 100,00 den Netto-Betrag abziehen und die enthaltene Mehrwertsteuer berechnen. Bei 19% sind das 15,9664 Euro.

    Ich möchte gerne wissen, wie diejenigen, die double-Werte bei Geldbeträgen 'kriminell' (oder sonstwie verkehrt) halten, das berechnen.

    Sagen wir mal 10000=1€, und sind damit auch vierstellig.
    1000000=100€
    1000000*100/119=840336
    1000000-840336=159664
    159664=15,9664€



  • Guten morgen volkard!

    volkard schrieb:

    mareb schrieb:

    Vielleicht war ich an der Stelle nicht deutlich genug, ich möchte vom Brutto-Betrag 100,00 den Netto-Betrag abziehen und die enthaltene Mehrwertsteuer berechnen. Bei 19% sind das 15,9664 Euro.

    Ich möchte gerne wissen, wie diejenigen, die double-Werte bei Geldbeträgen 'kriminell' (oder sonstwie verkehrt) halten, das berechnen.

    Sagen wir mal 10000=1€, und sind damit auch vierstellig.
    1000000=100€
    1000000*100/119=840336
    1000000-840336=159664
    159664=15,9664€

    Hey, guck mal einer an! Danke für Deine Antwort! Ich habe also viel zu kompliziert gedacht oder auf dem Schlauch gestanden...



  • Hallo volkard,
    die Formel versagt bei Steuersätzen wie 10,7%

    Aber viel muß man nicht ändern. Hier die int64-Funktion:

    Der Parameter pdecs gibt an, mit wieviel Stellen die prozent Zahl dargestellt wird. Will man mit 10,7% rechnen ruft man z.B. auf:

    int64 result = CPMoneyIncludedTax(1000000, 107, 1);
    

    oder

    int64 result = CPMoneyIncludedTax(1000000, 1070, 2);
    

    je nachdem, wie die Prozentzahl dargestellt wird.

    int64 CPMoneyIncludedTax(int64 Betrag, int64 prozent, int pdecs)
    {
        int64 faktP;
        int64 x, m;
        int64 fakt100 = 100;;
        int   tf = 2; /* => 100 */
        if(pdecs)
        {
            pdecs--;
            tf++;
        }
        if(pdecs)
        {
            pdecs--;
            tf++;
        }
        faktP   = potenz64(pdecs);
        fakt100 = potenz64(tf);
        x = fakt100 + (prozent / faktP);
        m = (Betrag * fakt100) / x; /* Netto-Betrag */
        x = Betrag - m;
        return x;
    }
    


  • Hallo,
    die einfache Funktion von Dir funktioniert auch nur bei ganzen Prozentzahlen wie 19 oder 7, geht aber nicht bei 10,7%. Deshalb poste ich mal meine korrigierte Version.

    cooky451 schrieb:

    Also ich hoffe mal ich übersehe hier jetzt nichts essenzielles, aber ich poste das trotzdem einfach mal..

    #define uint64 unsigned __int64
    
    uint64 vatax(uint64 amount, int vatax)
    {
      return (amount * vatax) / 100;
    }
    

    Der Parameter pdecs gibt an, mit wieviel Stellen die prozent Zahl dargestellt wird. Will man mit 10,7% rechnen ruft man z.B. auf:

    int64 result = CPMoneyTax(1000000, 1070, 2);
    
    int64 CPMoneyTax(int64 Betrag, int64 prozent, int pdecs)
    {
        int64 faktP;
        int64 fakt100 = 100;;
        int   tf = 2; /* => 100 */
        if(pdecs)
        {
            pdecs--;
            tf++;
        }
        if(pdecs)
        {
            pdecs--;
            tf++;
        }
        faktP   = potenz64(pdecs);
        fakt100 = potenz64(tf);
        int64 x = Betrag * (prozent / faktP);
        x = x / fakt100;
        return x;
    }
    


  • mareb schrieb:

    Hallo,
    die einfache Funktion von Dir funktioniert auch nur bei ganzen Prozentzahlen wie 19 oder 7, geht aber nicht bei 10,7%. Deshalb poste ich mal meine korrigierte Version.

    *100/119 war nicht falsch. Ebensowenig *1000/1007.


Anmelden zum Antworten