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

Hi
I know lots of floats are impossible to represent in 32bit IEEE754, but why is this rounding not preserved through simple arithmetic?
aka print $num is correct
but not print $num-int($num);

What is the easiest way to get rid of those?

$fracstr = sprintf("%.3f",$frac) ?

$ ./nice_num.pl 1234.123 = 1234 0.123000000000047 1000 = 1000 0 0.234 = 0 0.234 4.222 = 4 0.222 130.000 = 130 0 500 = 500 0 345678.345 = 345678 0.34499999997206

----------------------------------------------------

#!/usr/bin/perl -w ################################## # split number in int and fraction my $split_number = sub { my $num = shift; my $int = int($num); my $frac = $num - $int; return [$int,$frac]; }; # main my @testnums = qw(1234.123 1000 0.234 4.222 130.000 500 345678.345); for $n (@testnums) { print "$n = "; for $z (@{&$split_number($n)}) { print "$z "; } print "\n"; }

Thanks

20060113 Janitored by Corion: Added formatting, removed PRE tags

Replies are listed 'Best First'.
Re: simple arithmetic creates rounding errors
by reasonablekeith (Deacon) on Jan 13, 2006 at 10:14 UTC
    I don't think you can get rid of them, you just have to manage it. If you swap in the following line you'll get the results as you expect.
    my $frac = sprintf("%.9g", ($num - $int) );
    This is simply rounding to an arbitrary 9 decimal points. Obviously you need to look at the formulas you're working with but this should serve in a lot of cases.

    UPDATE: I didn't notice you actually gave a sprintf example. So, Yes, that is the easiest way to get rid of this problem. Infact the O'Reilly Perl CookBook gives examples just like this.
    ---
    my name's not Keith, and I'm not reasonable.
      Thanks reasonablekeith

      The "%.9g" fixed it. Unlike "%.3f" which produces .000 onto everything.

      Excellent!!!!

      I must look better through the cookbook next time :-)