I suspected that this was the intentional behavior of the function. For
what I am trying to do, I don't think "banker's rounding" will work. Not
being a "real" programmer, perhaps I am approaching my problem from the
wrong angle.
I am writing a script that works with a piece of CAM software to create a
drawn pattern. The total number of patterns I need will vary each time the
program is run, but the number will always be an integer. The trouble is
that I have to alternate the patterns from the left side of the design to
the right side of the design. When I have an even number of patterns, this
isn't a problem. $ patterns means two patterns on the left and two on the
right. The rule I must follow for odd numbers is to divide by two, round up
to the next highest number, and put the higher number of patterns on the
left. So for 5 patterns, I would have 3 on the left and two on the right.
What I am trying to do is to get the number of patterns, divide by two,
round up, then subtract this value from the total to obtain the right and
left numbers. So in my case I always want to round up. Unless there is a
better way to approach a problem like this....
Thanks for the help and the info. It helps a novice programmer such as
myself to understand things a bit better.
.-. --..
-----Original Message-----
From: zsdc [mailto:***@wp.pl]
Sent: Tuesday, February 24, 2004 2:29 PM
To: Zielfelder, Robert
Cc: Perl Beginners List (E-mail)
Subject: Re: Rounding of floating point numbers
Post by Robert ZielfelderIf $var is odd, $var2 rounds low. If $var is even, then $var2 rounds
high.
Post by Robert ZielfelderBeing a programmer by necessity rather than by choice forces me to take
the
Post by Robert Zielfeldereasy way out and use the POSIX solution to get the program written.
Although, it would be interesting to know why the sprintf method behaves
the
Didn't you mean the other way around, i.e. rounding to the nearest even
integer, instead of odd as you wrote above?
It's a banker rounding, an old way of rounding numbers used even in
times when bankers were doing it manually. It's a way to ensure that
your results are not skewed in any particular direction, to minimize the
accumulation of rounding errors after adding numbers together.
When the fraction part is exactly 0.5, i.e. it's equally far from both
integers it is between, then it rounds to the even one. Why even and not
odd? Only because it's easier to divide by 2 without introducing more
errors.
Run this program:
#!/usr/bin/perl -w
for $f (.49, .50, .51) {
for $i (0..5) {
printf "%.2f -> %.0f\n", $i + $f, $i + $f;
}
}
__END__
It will print:
0.49 -> 0
1.49 -> 1
2.49 -> 2
3.49 -> 3
4.49 -> 4
5.49 -> 5
0.50 -> 0
1.50 -> 2
2.50 -> 2
3.50 -> 4
4.50 -> 4
5.50 -> 6
0.51 -> 1
1.51 -> 2
2.51 -> 3
3.51 -> 4
4.51 -> 5
5.51 -> 6
Numbers with .49 are always rounded down (like with floor) to get the
nearest integer, numbers with .51 are always rounded up (like with ceil)
-- still, no problem with finding the nearest integer -- but numbers
with .50 not having a nearest integer, are rounded to the nerest even
integer.
This not Perl-specific at all. This C program:
#include <stdio.h>
int main() {
float i, f;
for (f = 0.49; f <= 0.51; f += 0.01)
for (i = 0; i <= 5; i++)
printf("%.2f -> %.0f\n", i + f, i + f);
return 0;
}
/* END */
prints exactly the same output as the above Perl program.
I haven't read everything in this thread so I don't know what results
are you exactly expecting, but I think that you probably should use
Math:: modules, like Charles suggested.
Do you want numbers with decimal part .5 to always round up? Keep in
mind that it will skew your results. See this program:
#!/usr/bin/perl -w
use POSIX qw(floor ceil);
sub round1 { sprintf '%.0f', @_ }
sub round2 {
$x = shift;
$r = floor($x);
if ($x - $r >= 0.5) { $r = ceil($x) }
return $r;
}
for (1..10000) {
$x = 0.1 * int rand 100;
$sum += $x;
$rsum1 += round1($x);
$rsum2 += round2($x);
}
printf "Real:\t%.1f\n", $sum;
print "Banker:\t$rsum1\n";
print "5up:\t$rsum2\n";
__END__
The function round1() rounds just like printf and the function round2()
rounds .5 always up. The program adds random numbers between 0.0 and 9.9
and prints the real sum and the sums of numbers rounded with both
methods. See that the second one is always considerably larger. Every
rounded number is skewed up by 5% on average. This is exactly why we use
banker rounding.
--
ZSDC