I decided to write my own rounding algorithm that takes it out of Perl's
hands and does all the math itself using strings.  Since it uses strings it
operates on the same literal value that a human would be looking at rather
than an opaque object.  Floats are better thought of as opaque objects than
numbers.  When u feed a float to the function Perl will stringify it first.

Here's the function.  It handles negative numbers and rounding to an
integer.  This rounding can be considered zero centered because an up round
moves the number away from zero and a down round moves the number toward
zero. It's not all encompassing though.  Asking it to round something like
-.00 will come back unpretty but still valid.  Canonicalizing everything to
a standard presentation will take some more code. The printf's are just
there for informational output.

sub sround {
        my ($num, $digits) = @_;
        my $neg;
        printf "num $num %0.32f $digits\n", $num;
        my ($int, $frac) = split /\./, $num;
        return $num if length $frac <= $digits;
        $neg = "-" and substr($int, 0, 1, "") if substr($int, 0, 1) eq "-";
        ## perform multiplication by 10^x
        $int .= substr($frac, 0, 1, "") foreach (1 .. $digits);
        ## actually round the low digit
        $int += 1 if substr($frac, 0, 1) >= 5;
        printf "int %0.25s - frac %0.32s\n", ($int, $frac);
        $frac = "";
        ## perform division by 10^x
        substr($frac, 0, 0, substr($int, -1, 1, "")) foreach (1 .. $digits);
        $frac = ".${frac}" if length $frac;
        $neg = "" unless "${int}${frac}" =~ m/[1-9]/;
        ## build and return final rounded number
        return "${neg}${int}${frac}";
}

I've tested it some and it handles everything %f dies on.
printf "$_ -> %.0f\n", $_ foreach (-.5, 0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5,
7.5, 8.5, 9.5);
print "$_ -> ", &sround($_, 0), "\n" foreach (-.45, -.5, 0.5, 1.5, 2.5, 3.5,
4.5, 5.5, 6.5, 7.5, 8.5, 9.5);
^D
-0.5 -> -0
0.5 -> 0
1.5 -> 2
2.5 -> 2
3.5 -> 4
4.5 -> 4
5.5 -> 6
6.5 -> 6
7.5 -> 8
8.5 -> 8
9.5 -> 10
-0.45 -> 0
-0.5 -> -1
0.5 -> 1
1.5 -> 2
2.5 -> 3
3.5 -> 4
4.5 -> 5
5.5 -> 6
6.5 -> 7
7.5 -> 8
8.5 -> 9
9.5 -> 10

D:\backups>perl \round.pl 3.49999999999999999 0
posix::modf:
num 3.49999999999999999 3.50000000000000000000000000000000 0
int 3.0000000000000000000000000 - frac 0.50000000000000000000000000000000
4
sround:
num 3.49999999999999999 3.50000000000000000000000000000000 0
int 3 - frac 49999999999999999
3

QED



--
REMEMBER THE WORLD TRADE CENTER         ---=< WTC 911 >=--
"...ne cede malis"

00000100

_______________________________________________
Perl-Win32-Users mailing list
[email protected]
To unsubscribe: http://listserv.ActiveState.com/mailman/mysubs

Reply via email to