DutchCoder has asked for the wisdom of the Perl Monks concerning the following question:

#!/usr/bin/perl -w use strict; my $ammount; my $value; my $response = qq{Value should be 189.81 (rounded to two decimals)} . qq{ and sprintf gives us: %.02f \n}; $ammount = 159.5; $value = $ammount * 1.19; print sprintf($response, $value); $ammount = 159.5; $value = ($ammount*119)/100; print sprintf($response, $value);

When using the first calculation, the value was off by 1 cent. This raised some eyebrows while evaluating our code.

Can someone shed a light on this behaviour?

Replies are listed 'Best First'.
Re: rounding variations after multiplication and division
by moritz (Cardinal) on Aug 06, 2009 at 12:30 UTC
      Thank you for your help.
Re: rounding variations after multiplication and division
by ig (Vicar) on Aug 06, 2009 at 12:35 UTC

    See also What Every Computer Scientist Should Know About Floating Point. And consider the following variation of your program:

    use strict; my $ammount; my $value; my $response = qq{Value should be 189.81 (rounded to two decimals)} . qq{ and sprintf gives us: %.24f \n}; $ammount = 159.5; $value = $ammount * 1.19; print sprintf($response, $value); $ammount = 159.5; $value = ($ammount*119)/100; print sprintf($response, $value);

    Which produces

    Value should be 189.81 (rounded to two decimals) and sprintf gives us: + 189.804999999999978399500833 Value should be 189.81 (rounded to two decimals) and sprintf gives us: + 189.805000000000006821210263

    You can clearly see from this output why sprintf rounds the two values differently.

      I had already used %.10f while debugging, but that wasn't enough. Nice example, tnx.
Re: [solved] rounding variations after multiplication and division
by roboticus (Chancellor) on Aug 07, 2009 at 00:12 UTC
    DutchCoder:

    For financial calculations, you'll want to avoid floating point. Instead, use fixed point arithmetic. I generally just use integers and then stuff in the decimal point in the output routines (when I'm displaying 'em--for file I/O, I don't insert the decimal point).

    ...roboticus