Results 1 to 13 of 13

Thread: Afrondingsverschil currency Delphi en Excel

  1. #1
    Fornicatorus Formicidae VideoRipper's Avatar
    Join Date
    Mar 2005
    Location
    Vicus Saltus Orientalem
    Posts
    5,708

    Afrondingsverschil currency Delphi en Excel

    Hallo vrienden,

    Ik zit me al een hele ochtend blind te staren en waarschijnlijk zie ik iets gewoon over het hoofd of begrijp ik de manier waarop Delphi bedragen (van het type currency) anders afrondt dan Excel.
    Ons pakket is al zo'n 20 jaar oud en de code waar ik nu mee geconfronteerd wordt is ook al een hele lange tijd in gebruik, echter nu blijken er verschillen te zijn tussen het pakket van ons en die van een andere partij en ik kan er maar niet de vinger op leggen.
    Ook nadat ik het stuk code (zie bijlage) tot een minimum heb gereduceerd zie ik het licht nog niet.

    Name:  Rounding.png
Views: 1068
Size:  4.7 KB

    Het gaat helemaal terug naar het getal 5,4949554
    Volgens Delphi is dit, afgerond naar 2 decimalen 5,50 terwijl Excel tot echt van mening is dat het 5,49 moet zijn.

    Ik snap het even niet meer; wie helpt mij verder?
    Attached Files Attached Files
    TMemoryLeak.Create(Nil);

  2. #2
    mov rax,marcov; push rax marcov's Avatar
    Join Date
    Apr 2004
    Location
    Ehv, Nl
    Posts
    10,357
    Ik weet het niet precies, maar het probleem zou het percentage van type double kunnen zijn, dat die delen van de expressie in double ipv currency uitvoert.

    Weet excel dat het currency is ? Zet je types van de cells oid?

  3. #3
    Het gaat helemaal terug naar het getal 5,4949554
    Dat kan niet in een currencyveld in Delphi.

    Currency in delphi heeft exact 4 posities achter de comma, daarna zijn het intern allemaal nullen. Dat maakt currency als type zo mooi.

    Het lijkt erop dat er ergens een conversie of zo plaats heeft naar een float of zo. Laat anders eens wat code zien.

  4. #4
    mov rax,marcov; push rax marcov's Avatar
    Join Date
    Apr 2004
    Location
    Ehv, Nl
    Posts
    10,357
    Ja dat mengen van currency en float was mijn gevoel ook, en zoals gezegd het percentage in

    Code:
    function CalcAmount(AChargeAmount: Currency; APercentage: Double; AQty: Integer): Currency;
    begin
      Result := ((AChargeAmount / AQty) * (APercentage / 100)) * AQty;
    end;
    is zo'n geval

  5. #5
    Fornicatorus Formicidae VideoRipper's Avatar
    Join Date
    Mar 2005
    Location
    Vicus Saltus Orientalem
    Posts
    5,708
    Oorspronkelijk was het percentage ook als currency gedeclareerd en werd er (door de gebruiker) een getal als string ingevuld in de database, welke later weer als float werd ingelezen naar het percentage-veld (als currency).
    Eerst dacht ik dat het snel gefixt was door de currency (van percentage) te veranderen naar double maar daarmee was het probleem helaas nog niet opgelost.

    Het "Grappige" is dat Excel mij roet in de ogen gooide toen ik speelde met de decimals waarde in het dialoogvenster waar je het veldtype kunt aanpassen:
    Click image for larger version. 

Name:	Excel-8.png 
Views:	96 
Size:	15.5 KB 
ID:	8136

    Ga je namelijk spelen met de "Decimal places" waarde, dan krijg je deze resultaten (van 8 decimalen naar 2 decimalen achter de komma):
    5,49495540 => 5,4949554 => 5,494955 => 5,49496 => 5,4950 => 5,495 => 5,49

    Mijn (onterechte) aanname was dat elke stap op zichzelf zou staan: wanneer je dus gewoon de Delphi uitkomst (5,4950) zou gebruiken, dat dan de uitkomsten identiek zouden zijn.
    Maar nee: vul ik alleen 5,4950 in als waarde in Excel en rond ik die af op twee decimalen, dan maakt Excel daar ook (of wél) 5,50 van:
    Click image for larger version. 

Name:	Excel-2.png 
Views:	109 
Size:	14.6 KB 
ID:	8137

    Het is dus daadwerkelijk belangrijk wat de waarde oorspronkelijk was (met al zijn decimalen).

    Neemt niet weg dat ik de manier van afronden apart vind; dit is een van mijn eerdere notities (volgens de "Normale" afrondingsregels):
    • 5,4949554 removing the 4 makes it 5,494955
    • 5,494955 removing the 5 makes it 5,49496
    • 5,49496 removing the 6 makes it 5,4950
    • 5,4950 removing the 0 makes it 5,495
    • 5,495 removing the 5 makes it 5,50
    TMemoryLeak.Create(Nil);

  6. #6
    Quote Originally Posted by VideoRipper View Post
    ... (volgens de "Normale" afrondingsregels):
    • 5,4949554 removing the 4 makes it 5,494955
    • 5,494955 removing the 5 makes it 5,49496
    • 5,49496 removing the 6 makes it 5,4950
    • 5,4950 removing the 0 makes it 5,495
    • 5,495 removing the 5 makes it 5,50
    Volgens mij is dat niet "normaal".
    5.494999999999999 is afgerond op 2 decimalen 5.49, niet 5.50
    5.49499999 is echt dichter bij 5.49 dan bij 5.50.
    Volgens jouw spelregels zou zelfs 5.494444444444444444444444444444444444444444444444 4444444444444444444444444444444444444445 dan 5.50 opleveren.

    Bart

  7. #7
    Silly member NGLN's Avatar
    Join Date
    Aug 2004
    Location
    Werkendam
    Posts
    5,133
    Excel doet het op de volgende en volgens mij enige juiste manier:
    • 5,4949554 removing the 49554 makes it 5,49


    Het type Currency in Delphi rekent met een significantie van 4 decimalen achter de komma. Dat betekent dat het type Currency jouw getal afrond op de volgende manier:
    • 5,4949554 removing the 554 makes it 5,4950

    Als je dat vervolgens wilt weergeven met 2 decimalen houdt je inderdaad 5,45 over.

    De enige manier om de afronding van Excel te krijgen is om geen gebruik te maken van het type Currency:
    Delphi Code:
    1. edtResult.Text := FloatToStrF(CalcAmount(cAmount, dPerc, edtQuantity.Value),
    2.                                  ffCurrency, 16, edtDigits.Value, FFormatSettings);
    Let op dat hierbij de Precision het totaal aantal significante cijfers betreft, niet alleen die achter de komma.

    Echter, dergelijke kleine afrondingsverschillen zijn zeer gebruikelijk, goed verklaarbaar en volgens mij volledig geaccepteerd. Vrijwel alle boekhoudsystemen hebben dan ook de mogelijkheid hiermee om te gaan.

    Overigens, in jouw formule streept / AQty tegen * AQty weg. Ik vermoed dat de formule moet zijn:
    Delphi Code:
    1. Result := AChargeAmount * (APercentage / 100) * AQty;

    En als afsluiter hierbij nog iemand met dezelfde vraag.
    Last edited by NGLN; 20-Nov-20 at 16:36.
    (Sender as TNLDUser).Signature := 'Groeten van Albert';

  8. #8
    Silly member NGLN's Avatar
    Join Date
    Aug 2004
    Location
    Werkendam
    Posts
    5,133
    Kortom: wat Bart zegt.
    (Sender as TNLDUser).Signature := 'Groeten van Albert';

  9. #9
    Fornicatorus Formicidae VideoRipper's Avatar
    Join Date
    Mar 2005
    Location
    Vicus Saltus Orientalem
    Posts
    5,708

    Thumbs up

    Zoals in mijn beginpost al zei
    Quote Originally Posted by VideoRipper View Post
    Ik zit me al een hele ochtend blind te staren
    Uiteindelijk blijkt het niet aan de formule zelf te liggen (AQty wordt niet weggestreept, maar we moeten binnen de berekening de eenheidsprijs weten bij een opgegeven aantal en prijs; ik heb het ook niet bedacht), maar aan het stukje code dat ik als oorzaak van het probleem had uitgesloten en dus niet mee had genomen in mijn voorbeeld omdat het in de oorspronkelijk opzet (met het percentage nog als currency) niets uit leek te maken.

    Delphi Code:
    1. function RoundFinancial(Amount: Currency): Currency;
    2.  
    3.   function RealRound(a: Extended): Extended;
    4.   begin
    5.     if a >= 0 then
    6.       Result := Int(a + 0.5)
    7.     else
    8.       Result := Int(a - 0.5);
    9.   end;
    10.  
    11. begin
    12.   Result := RealRound(Amount * Power(10, gDecimalPlaces)) / Power(10, gDecimalPlaces);
    13. end;

    De oorspronkelijke formule was namelijk:
    Delphi Code:
    1. Result := RoundFinancial((AChargeAmount / AQty) * (APercentage / 100)) * AQty;

    Verander ik de declaratie van...
    Delphi Code:
    1. function RoundFinancial(Amount: Currency): Currency;
    ...in...
    Delphi Code:
    1. function RoundFinancial(Amount: Double): Currency;
    ...dan klopt het resultaat wel gewoon.

    Nou moet ik alleen kijken of een dergelijke aanpassing andere gevolgen heeft voor de pakket
    Bovenstaande functie wordt op "Slechts" 290 andere plekken aangeroepen en in de afgelopen 20 jaar hebben er regelmatig "Knippers en plakkers" aan het pakket gewerkt, die een snelle oplossing belangrijker vonden dan een probleem bij de bron aan te pakken.

    Bedankt voor meedenken in ieder geval!
    TMemoryLeak.Create(Nil);

  10. #10
    Quote Originally Posted by VideoRipper View Post
    Bovenstaande functie wordt op "Slechts" 290 andere plekken aangeroepen en in de afgelopen 20 jaar hebben er regelmatig "Knippers en plakkers" aan het pakket gewerkt, die een snelle oplossing belangrijker vonden dan een probleem bij de bron aan te pakken.
    Nou, ik benijd je niet.

    Bart
    Last edited by Bart B; 20-Nov-20 at 19:30. Reason: quote bijgetrimd

  11. #11
    John Kuiper
    Join Date
    Apr 2007
    Location
    Almere
    Posts
    8,747
    Quote Originally Posted by Bart B View Post
    Nou, ik benijd je niet.

    Bart
    +1

    Dit zelfde probleem heb ik met mijn reportgenerator
    Delphi is great. Lazarus is more powerfull

  12. #12
    Hallo,

    Om correct te kunnen afronden kijk dan ook een hier: https://www.wiskunde.eu/wiskunde-the...basis/afronden

    H.G. Frans

  13. #13
    Fornicatorus Formicidae VideoRipper's Avatar
    Join Date
    Mar 2005
    Location
    Vicus Saltus Orientalem
    Posts
    5,708
    Bedankt Frans, ik was er inmiddels al achter gekomen dat de 35 jaar tussen middelbare school en nu wat elementaire basiskennis heeft laten verwateren.
    TMemoryLeak.Create(Nil);

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •