Freeware JavaScript Editor Perl Tutorials

↑

Main Page |

## Recipe 2.2 Rounding Floating-Point Numbers## 2.2.1 ProblemYou want to round a floating-point value to a certain number of decimal places. This problem arises from the same inaccuracies in representation that make testing for equality difficult (see Recipe 2.3), as well as in situations where you must reduce the precision of your answers for readability. ## 2.2.2 Solution
Use the Perl function
# round off to two places $rounded = sprintf("%.2f"", $unrounded); Or you can use other rounding functions described in the Discussion. ## 2.2.3 DiscussionWhether visible or not, rounding of some sort is virtually unavoidable when working with floating-point numbers. Carefully defined standards (namely, IEEE 754, the standard for binary floating-point arithmetic) coupled with reasonable defaults within Perl often manage to eliminate or at least hide these round-off errors. In fact, Perl's implicit rounding on output is usually good enough so
that it rarely surprises. It's almost always best to leave the
numbers unrounded until output, and then, if you don't like Perl's
default rounding, use for $n ( 0.0000001, 10.1, 10.00001, 100000.1 ) { printf "%12.4e %12.4f %12.4g\n", $n, $n, $n; } This produces the following output: 1.0000e-07 0.0000 1e-07 1.0100e+01 10.1000 10.1 1.0000e+01 10.0000 10 1.0000e+05 100000.1000 1e+05 If that were all there were to the matter, rounding would be pretty easy. You'd just pick your favorite output format and be done with it. However, it's not that easy: sometimes you need to think more about what you really want and what's really happening. As we explained in the Introduction, even a simple number like 10.1 or 0.1 can only be approximated in binary floating-point. The only decimal numbers that can be exactly represented as floating-point numbers are those that can be rewritten as a finite sum of one or more fractions whose denominators are all powers of two. For example: $a = 0.625; # 1/2 + 1/8 $b = 0.725; # 725/1000, or 29/40 printf "$_ is %.30g\n", $_ for $a, $b; prints out: 0.625 is 0.625 0.725 is 0.724999999999999977795539507497 The number in Usually the round-off error is so small you never even notice it, and
if you do, you can always specify how much precision you'd like in
your output. But because the underlying approximation is still a
little bit off from what a simple $a = 0.325; # 1/2 + 1/8 $b = 0.725; # 725/1000, or 29/40 printf "%s is %.2f or %.30g\n", ($_) x 3 for $a, $b; This produces: 0.325 is 0.33 or 0.325000000000000011102230246252 0.725 is 0.72 or 0.724999999999999977795539507497 Since 0.325's approximation is a bit above that, it rounds up to 0.33. On the other hand, 0.725's approximation is really a little under that, so it rounds down, giving 0.72 instead. But what about if the number is exactly representable, such 1.5 or 7.5, since those are just whole numbers plus one-half? The rounding rule used in that case is probably not the one you learned in grade school. Watch: for $n (-4 .. +4) { $n += 0.5; printf "%4.1f %2.0f\n", $n, $n; } That produces this: -3.5 -4 -2.5 -2 -1.5 -2 -0.5 -0 0.5 0 1.5 2 2.5 2 3.5 4 4.5 4 What's happening is that the rounding rule preferred by numerical analysts isn't "round up on a five," but instead "round toward even." This way the bias in the round-off error tends to cancel itself out.
Three useful
functions for rounding floating-point values to integral ones are
use POSIX qw(floor ceil); printf "%8s %8s %8s %8s %8s\n", qw(number even zero down up); for $n (-6 .. +6) { $n += 0.5; printf "%8g %8.0f %8s %8s %8s\n", $n, $n, int($n), floor($n), ceil($n); } This produces the following illustrative table; each column heading shows what happens when you round the number in the specified direction. number even zero down up -5.5 -6 -5 -6 -5 -4.5 -4 -4 -5 -4 -3.5 -4 -3 -4 -3 -2.5 -2 -2 -3 -2 -1.5 -2 -1 -2 -1 -0.5 -0 0 -1 0 0.5 0 0 0 1 1.5 2 1 1 2 2.5 2 2 2 3 3.5 4 3 3 4 4.5 4 4 4 5 5.5 6 5 5 6 6.5 6 6 6 7 If you add up each column, you'll see that you arrive at rather different totals: 6.5 6 6 0 13 What this tells you is that your choice of rounding style—in effect, your choice of round-off error—can have tremendous impact on the final outcome. That's one reason why you're strongly advised to wait until final output for any rounding. Even still, some algorithms are more sensitive than others to accumulation of round-off error. In particularly delicate applications, such as financial computations and thermonuclear missiles, prudent programmers will implement their own rounding functions instead of relying on their computers' built-in logic, or lack thereof. (A good textbook on numerical analysis is also recommended.) ## 2.2.4 See AlsoThe |

Main Page |

↓

JavaScript Verifier Perl Tutorials

©