I have to deal with a rounding issue which basically goes back to high- precision calculations. The issue is that the outcome is already known and should match.
- Is there any way to perform the calculations at extreme high precision, so that all caculated alphanumerics match ?
- I have a known outcome (let's say eg. 8577.77) which was done already in javascript by another application; is there a way to guarantee that both outcomes are identical ?
- I have the feeling that this is maybe a common situation, are there 'classical' approaches for this kind of things ?
- If I want to manually check the order, the calculations must match (e.g. 'Net'+'Tax' must equal to 'Brut')
> I have to deal with a rounding issue which basically goes back to high- > precision calculations. The issue is that the outcome is already known > and should match.
> - Is there any way to perform the calculations at extreme > high precision, so that all caculated alphanumerics match ?
> - I have a known outcome (let's say eg. 8577.77) which was > done already in javascript by another application; is there > a way to guarantee that both outcomes are identical ?
> - I have the feeling that this is maybe a common situation, > are there 'classical' approaches for this kind of things ?
> - If I want to manually check the order, the calculations > must match (e.g. 'Net'+'Tax' must equal to 'Brut')
Obviously you are doing something with money. In that case you usually do NOT need extreme high precision because there are defined rules how and when to round to how many digits.
It might be that you need to round to 2 (or 4) digits behind the decimal point after each step.
So I can only give the advice to really look into the law how to add the tax correctly and to find out what the contract with the commission dealer really says.
-- Tad McClellan email: perl -le "print scalar reverse qq/moc.liamg\100cm.j.dat/" The above message is a Usenet post. I don't recall having given anyone permission to use it on a Web site.
>I have to deal with a rounding issue which basically goes back to high- >precision calculations.
Actually it doesn't. It goes back to understanding how calculations work, e.g. basic computer numeric as well as basic rules for accounting.
>The issue is that the outcome is already known >and should match.
Then you should follow the same processes and rules that resulted in the already known outcome.
[...]
>- Is there any way to perform the calculations at extreme > high precision,
Yes, it is called symbolic calculations and there are more or less expensive computer programs out there that do those. But that doesn't help you one bit, because ...
>so that all caculated alphanumerics match ?
... the already known outcome was not computed using extreme high precision, either.
>- I have a known outcome (let's say eg. 8577.77) which was > done already in javascript by another application; is there > a way to guarantee that both outcomes are identical ?
Yes. Use the same rules as have been used in the other application.
>- I have the feeling that this is maybe a common situation,
Yes. It is the misguided believe that higher precision equals better results. THAT IS NOT THE CASE. You should do your computations using the same method that was used in the other application using the same precision and the same mathematical operators with the same behaviour and the same algorithm. In your case you should specifically check with accountants about how sums are computed. Trivial example: if the commision is computed for each individual transaction, listed in e.g. Euro and Cent, and then added, then you will usually get a different result compared to adding all transactions and then computing the commision on the total sales.
> are there 'classical' approaches for this kind of things ?
Yes, see Introduction into Basic Numerics for Computer Scientists
>- If I want to manually check the order, the calculations > must match (e.g. 'Net'+'Tax' must equal to 'Brut')
Then you need to calculate them the same way as they were calculated in the other application..
On May 13, 7:19 am, Bart Van der Donck <b...@nijlen.com> wrote:
> Hello,
> I have to deal with a rounding issue which basically goes back to high- > precision calculations. The issue is that the outcome is already known > and should match.
> - Is there any way to perform the calculations at extreme > high precision, so that all caculated alphanumerics match ?
convert to cents I think. Then when ready to output, convert back to dollars (do not use sprintf "%.2f"). Instead, use the substitution operator:
# Convert to pennies from dollars. # $price is now an integer $price =~ s/\.(?=\d\d$)// or die "Cannot expand $price to integer. $!";
# convert from pennies to dollars, (insert decimal point), for output. s/(\d\d)$/.$1/ for $price, $net, $brut;
> - I have a known outcome (let's say eg. 8577.77) which was > done already in javascript by another application; is there > a way to guarantee that both outcomes are identical ?
> - I have the feeling that this is maybe a common situation, > are there 'classical' approaches for this kind of things ?
> - If I want to manually check the order, the calculations > must match (e.g. 'Net'+'Tax' must equal to 'Brut')
> Thank you,
> -- > Bart
Hi Bart,
FWIW, I believe my code (below) exhibits Pennsylvania's sales tax.
#!/usr/bin/perl use strict; use warnings; use 5.012; use POSIX qw/ ceil /;
for my $cents (1 .. 111) { my $tax = ceil($cents * .06); my $scale = $cents % 100; $tax-- if $scale >= 1 && $scale <= 10; say "$cents $tax";
}
Note that this state (perhaps others too) take the 'ceil(ing)' of the cents. (Use cents because I am now dealing with integers). Then it is necessary to convert back to dollars for output purposes.
On May 21, 6:15 pm, "Peter J. Holzer" <hjp-usen...@hjp.at> wrote:
> On 2011-05-21 21:52, char...@pulsenet.com <char...@pulsenet.com> wrote:
> > convert to cents I think. > > Then when ready to output, convert back to dollars (do not use sprintf > > "%.2f").
> Why not? Can you show a case where it produces the wrong result?
No, I was assuming that by avoiding the sprintf I could avoid a rounding error.
> OTOH:
> > # convert from pennies to dollars, (insert decimal point), for > > output. > > s/(\d\d)$/.$1/ for $price, $net, $brut;
> This will not work for amount <= 99 cents.
Good catch. I think you meant it will not work for <= 9 cents. No match and no placement of the decimal point. I should have been more careful in uncharted (for me) territory. s/(\d\d?)$/.$1/ would be the correct answer I believe?
> > my $tax = ceil($cents * .06);
> my $tax = ceil($cents * 6 / 100);
> otherwise you multiply with > 0.059999999999999997779553950749686919152736663818359375 which may or > may not make a difference.
On 2011-05-21 23:55, char...@pulsenet.com <char...@pulsenet.com> wrote:
> On May 21, 6:15 pm, "Peter J. Holzer" <hjp-usen...@hjp.at> wrote: >> On 2011-05-21 21:52, char...@pulsenet.com <char...@pulsenet.com> wrote:
>> > convert to cents I think. >> > Then when ready to output, convert back to dollars (do not use sprintf >> > "%.2f").
>> Why not? Can you show a case where it produces the wrong result?
> No, I was assuming that by avoiding the sprintf I could avoid a > rounding error.
If you use sprintf("%.2f", $x/100) there will indeed be a rounding error in the computation of $x/100 and possibly another one in rounding two digits. Those rounding errors will be somewhere in the magnitude of $x/100/2**53 (assuming IEEE double precision floating point arithmetic), and as long as that error is less than 0.005, it won't affect the result. So $x/100/2**53 <= 0.005, therefore $x <= 0.005 * 2**53 * 100 or $x <= 4.5E15. Lets be conservative and say you're safe if $x is less than 1E14.
>> OTOH:
>> > # convert from pennies to dollars, (insert decimal point), for >> > output. >> > s/(\d\d)$/.$1/ for $price, $net, $brut;
>> This will not work for amount <= 99 cents.
> Good catch. I think you meant it will not work for <= 9 cents. No > match and no placement of the decimal point.
Actually I meant <= 99 cents, but I realize that there are locales where ".99" (instead of "0.99") is correct. So if your bean counter doesn't throw a hissy fit over the missing zero, that's ok. For <= 9 cents it's always incorrect.
> I should have been more careful in uncharted (for me) territory. > s/(\d\d?)$/.$1/ would be the correct answer I believe?
No that converts 9 to ".9" instead of ".09".
This would work:
for my $cents (9, 99, 999, 999_999_999_999) { my $dollars = sprintf("%03.0f", $cents); $dollars =~ s/(\d\d)$/.$1/; print "$cents -> $dollars\n";
>- Is there any way to perform the calculations at extreme > high precision, so that all caculated alphanumerics match ?
>- I have a known outcome (let's say eg. 8577.77) which was > done already in javascript by another application; is there > a way to guarantee that both outcomes are identical ?
>- I have the feeling that this is maybe a common situation, > are there 'classical' approaches for this kind of things ?
>- If I want to manually check the order, the calculations > must match (e.g. 'Net'+'Tax' must equal to 'Brut')
>Thank you,
There could be a typo in your numbers/code.
If the Brut total were to be 8577.77 , the Net and Tax totals would be significantly alterred. So, I asume you are not giving the exact input/output from the code where you state the known outcome of the Brut total of 8577.77
The reason I know this is that :
1) Net/Tax/Brut intermediate values are all interrelated.
2) Applying arithmetic significance of measured values do not alter the results. ie.. percent ~ 1.2958685 does not alter the outcome (a measured value) factor ~ 0.8567 is the least significant (also a measured value)
3) Applying sprintf "%.4f" to $brut intermediate raises the Brut total at the expence of Tax and Net. Even then, it only raises Brut to 8577.75
4) Rounding percent and factor to make Brut fit in the 8577.77 range, significantly alters Tax and Net.
I think its probable there is some other non-mathmatical error going on here.