develooper Front page | perl.beginners | Postings from April 2010

Re: Perl rounding errors?

Thread Previous | Thread Next
From:
John W. Krahn
Date:
April 26, 2010 11:04
Subject:
Re: Perl rounding errors?
Message ID:
4BD5D5BB.8090708@shaw.ca
Rob Coops wrote:
> 
> Thank you all that replied, in the end I copied the rules I learned in
> elementary school about how to round a number to two decimals. I'm sure it
> is a horrible hack and can be done a lot faster, but with a country not
> being able to process their invoices into the accounting system this was the
> best way I could come up with that didn't in some cases result in a error.
> I am not using any of the suggested modules because the production system is
> outside of my control and getting a module installed can take days if not
> longer due to processes procedures forms and so on. The country has only a
> few days left till the end of the month by which time this should absolutely
> be working.
> 
> This is the routine as it looks now (I would be happy to hear about errors
> or improvements that you might see)
> sub round {
>  my $number = shift;
>  if ( $number == 0 ) { return 0.00; }
>  if ( length( $number ) <= 4 ) { return $number; }
>  my $int = int( $number ); # Get the whole number
>  my $dec = $number - $int; # Get the decimals only
> 
>  $dec = sprintf( "%.15f", $dec ) * 1000000000000000;
> 
>  my @digits = split( //, $dec );
>  my @reverse_digits = reverse( @digits );
>  my $number_of_digits = $#reverse_digits - 1;
> 
>  my $remember = 0;
>  my $tracker = 0;
>  for( my $x = 0; $x <= $number_of_digits; $x++ ) {
>   $reverse_digits[$x] = $reverse_digits[$x] + $remember;
>   my $result = $reverse_digits[$x] + 5;
>   if ( $result >= 10 ) {
>    $remember = 1;
>   } else {
>    $remember = 0;
>   }
>   $tracker = $x;
>  }
> 
>  if ( $reverse_digits[$tracker] >= 10 ) {
>   $reverse_digits[$tracker] = $reverse_digits[$tracker] - 10;
>   $reverse_digits[$tracker + 1]++;
>   if ( $reverse_digits[$tracker + 1] == 10 ) {
>     $reverse_digits[$tracker + 1] = 0;
>     $int++;
>   }
>  }
>  my @reordered_digits = reverse(@reverse_digits);
>  splice( @reordered_digits, 2 );
>  my $decimal_amount = join( '', @reordered_digits );
>  return "$int.$decimal_amount";
> }

I tried it out.  Is this supposed to be correct?

$ perl Perl_rounding_errors.pl
0.524 --> 0.52
0.5241 --> 0.52
0.5242 --> 0.52
0.5243 --> 0.52
0.5244 --> 0.52
0.5245 --> 0.53
0.5246 --> 0.53
0.5247 --> 0.53
0.5248 --> 0.53
0.5249 --> 0.53




John
-- 
The programmer is fighting against the two most
destructive forces in the universe: entropy and
human stupidity.               -- Damian Conway

Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About