Account Options

  1. Sign in
The old Google Groups will be going away soon, but your browser is incompatible with the new version.
Google Groups Home
« Groups Home
Rounding issue with defined outcome
There are currently too many topics in this group that display first. To make this topic appear first, remove this option from another topic.
There was an error processing your request. Please try again.
flag
  9 messages - Collapse all  -  Translate all to Translated (View all originals)
The group you are posting to is a Usenet group. Messages posted to this group will make your email address visible to anyone on the Internet.
Your reply message has not been sent.
Your post was successful
 
From:
To:
Cc:
Followup To:
Add Cc | Add Followup-to | Edit Subject
Subject:
Validation:
For verification purposes please type the characters you see in the picture below or the numbers you hear by clicking the accessibility icon. Listen and type the numbers you hear
 
Bart Van der Donck  
View profile  
 More options May 13 2011, 7:19 am
Newsgroups: comp.lang.perl.misc
From: Bart Van der Donck <b...@nijlen.com>
Date: Fri, 13 May 2011 04:19:39 -0700 (PDT)
Local: Fri, May 13 2011 7:19 am
Subject: Rounding issue with defined outcome
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.

----------------------------------------------------------------
Code:
----------------------------------------------------------------

#!/usr/bin/perl
use strict;
use warnings;
my $TOTEXC = 0;
my $TOTINC = 0;
my $TOTTAX = 0;
my @products = ( # product name, price, tax%, quantity
                 'Screen|506.21|21|4',
                 'Cables|425.50|21|5',
                 'Server|585.26|21|1',
                 'Battery|58.62|21|3',
                 'Keyb.|44.46|21|2',
                 'Mouse|15.25|21|6',
                 'Battery|66.03|21|5'
               );
my $percent = 1.2958684232587526; # commission dealer
my $factor = 0.8567; # some fixed factor

print qq{\nPROD\tPRICE\tQUANT\tNET\tTAX\tBRUT\n};
for (@products)
{
  my ($prodname, $price, $tax, $quantity) = split /\|/, $_;
  $price = ( $price + ($price * $factor / 100) ) * $percent;
  my $net = $price * $quantity;
  my $brut = $net * ( 1 + ($tax / 100));
  $TOTEXC+= $net;
  $TOTINC+= $brut;
  $TOTTAX+= $brut - $net;
  $_ = sprintf("%.2f", $_) for ($price, $net, $brut);
  print qq{$prodname\t$price\t$quantity\t$net\t$tax%\t$brut\n};

}

$_ = sprintf("%.2f", $_) for ($TOTEXC, $TOTINC, $TOTTAX);
print qq{\nNet: $TOTEXC\nTax: $TOTTAX\nBrut: $TOTINC\n};

----------------------------------------------------------------
Output:
----------------------------------------------------------------

PROD    PRICE   QUANT   NET     TAX     BRUT
Screen  661.60  4       2646.41 21%     3202.15
Cables  556.12  5       2780.58 21%     3364.50
Server  764.92  1       764.92  21%     925.55
Battery 76.61   3       229.84  21%     278.11
Keyb.   58.11   2       116.22  21%     140.62
Mouse   19.93   6       119.59  21%     144.70
Battery 86.30   5       431.50  21%     522.11

Net: 7089.05
Tax: 1488.70
Brut: 8577.74

----------------------------------------------------------------
Questions:
----------------------------------------------------------------

- 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,

--
 Bart


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Wolf Behrenhoff  
View profile  
 More options May 13 2011, 7:39 am
Newsgroups: comp.lang.perl.misc
From: Wolf Behrenhoff <NoSpamPleaseButThisIsVal...@gmx.net>
Date: Fri, 13 May 2011 13:39:56 +0200
Local: Fri, May 13 2011 7:39 am
Subject: Re: Rounding issue with defined outcome
On 13.05.2011 13:19, Bart Van der Donck wrote:

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.

Wolf


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Tad McClellan  
View profile  
 More options May 13 2011, 7:48 am
Newsgroups: comp.lang.perl.misc
From: Tad McClellan <ta...@seesig.invalid>
Date: Fri, 13 May 2011 06:48:25 -0500
Local: Fri, May 13 2011 7:48 am
Subject: Re: Rounding issue with defined outcome
Bart Van der Donck <b...@nijlen.com> wrote:

> my $percent = 1.2958684232587526; # commission dealer

Add this, and look carefully at the output it makes:

    printf "%30.20f\n", $percent;

So things are wrong even before you start making any calculations...

> - I have the feeling that this is maybe a common situation,

Yes it is, and it is not restricted to Perl.

This problem applies to how numbers are stored in computers.

>   are there 'classical' approaches for this kind of things ?

    perldoc perlnumber

See also: What Every Computer Scientist Should Know About Floating-Point
Arithmetic

    http://download.oracle.com/docs/cd/E19957-01/806-3568/ncg_goldberg.html

--
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.


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Jürgen Exner  
View profile  
 More options May 20 2011, 11:53 pm
Newsgroups: comp.lang.perl.misc
From: Jürgen Exner <jurge...@hotmail.com>
Date: Fri, 20 May 2011 20:53:44 -0700
Local: Fri, May 20 2011 11:53 pm
Subject: Re: Rounding issue with defined outcome
Bart Van der Donck <b...@nijlen.com> wrote:

>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..

jue


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
char...@pulsenet.com  
View profile  
 More options May 21 2011, 5:52 pm
Newsgroups: comp.lang.perl.misc
From: char...@pulsenet.com
Date: Sat, 21 May 2011 14:52:37 -0700 (PDT)
Local: Sat, May 21 2011 5:52 pm
Subject: Re: Rounding issue with defined outcome
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.

[snip code]

> Questions:
> ----------------------------------------------------------------

> - 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.

Chris


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Peter J. Holzer  
View profile  
 More options May 21 2011, 6:15 pm
Newsgroups: comp.lang.perl.misc
From: "Peter J. Holzer" <hjp-usen...@hjp.at>
Date: Sun, 22 May 2011 00:15:43 +0200
Local: Sat, May 21 2011 6:15 pm
Subject: Re: Rounding issue with defined outcome
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?

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.

>    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.

        hp


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
char...@pulsenet.com  
View profile  
 More options May 21 2011, 7:55 pm
Newsgroups: comp.lang.perl.misc
From: char...@pulsenet.com
Date: Sat, 21 May 2011 16:55:27 -0700 (PDT)
Local: Sat, May 21 2011 7:55 pm
Subject: Re: Rounding issue with defined outcome
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.

0 for 3. Not very good.


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Peter J. Holzer  
View profile  
 More options May 22 2011, 10:51 am
Newsgroups: comp.lang.perl.misc
From: "Peter J. Holzer" <hjp-usen...@hjp.at>
Date: Sun, 22 May 2011 16:51:08 +0200
Local: Sun, May 22 2011 10:51 am
Subject: Re: Rounding issue with defined outcome
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";

}

        hp

 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
s...@netherlands.com  
View profile  
 More options May 22 2011, 2:24 pm
Newsgroups: comp.lang.perl.misc
From: s...@netherlands.com
Date: Sun, 22 May 2011 11:24:07 -0700
Local: Sun, May 22 2011 2:24 pm
Subject: Re: Rounding issue with defined outcome
On Fri, 13 May 2011 04:19:39 -0700 (PDT), Bart Van der Donck <b...@nijlen.com> wrote:

[snip code]

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.

-sln


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
End of messages
« Back to Discussions « Newer topic     Older topic »