On Mon, Apr 26, 2010 at 8:04 PM, John W. Krahn <jwkr...@shaw.ca> wrote:

> 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
>
> --
> To unsubscribe, e-mail: beginners-unsubscr...@perl.org
> For additional commands, e-mail: beginners-h...@perl.org
> http://learn.perl.org/
>
>
> Hi John,

Weirdly enough this is how the Uniface system feeding me the numbers rounds
them, since this is the system used in 32 countries and accepted by all the
tax authorities I have to emulate that rounding of numbers. I would indeed
have done the more correct methods but unfortunately they do not match the
magic of Uniface.
As the users look in the Uniface system and compare the numbers with what I
feed into the accounting system I cannot do anything else but copy that
behaviour.

@Uri, returning 0 or 0.00 does make a small difference in that the receiving
program likes the 0.00 better then the plain 0 don't ask me why ask our
mainframe colleagues why. I wish I could let perl do the work for me but it
simply does not regardless of how I try and do it return the "right" numbers
when I compare them with the numbers in the Uniface system. I have a sample
set of a month worth of invoices for 1 country and the below code is the
only way in which I was able to emulate the behaviour of the Uniface system
in all cases. My feeling is that the Uniface system does the same kind of
weird trick.

I have tried pretty much all Math::*, POSIX and other rounding libraries I
could find on CPAN and they all ended up with a few cents different here and
there. Now I know and can see that those libraries make a lot more sense and
actually produce correct results in pretty much all situations but
unfortunately mine is not one of them. As for the sanity of using Uniface...
I just hope that when the Uniface version is updated from 7 to 9 or 10 this
rounding algorithm doesn't change, though I would not be surprised if it
does.

Reply via email to