- Subscribe to RSS Feed
- Mark as New
- Mark as Read
- Bookmark
- Subscribe
- Printer Friendly Page
- Report Inappropriate Content
Sometimes you'd rather show "265" on the screen instead of "265.39128376465" — perhaps because it's just easier to understand, or perhaps because the calculation that yielded that very precise looking number really isn't all that precise in the first place, and you don't want to mislead the user. The usual way to deal with this issue is by "rounding", and you've probably been doing this since grade school. Even so, you may not realize just how complex a subject rounding actually is — so we're going to take this opportunity to make what you thought was a very simple subject into something far more complex and confusing than you ever thought it could be!
Most commonly when we think of rounding, we think of rounding to the nearest integer value, like in the example above. Most of us learned in school that if the value is exactly halfway between the two nearest integers, then we round up. For example, we'd round 2.5 up to 3. But this simple method that we were taught isn't always what we want. For starters, it's not always the case that we want to round to the nearest integer. For example, if we were dealing with eggs (21 eggs rounds to 2 dozen, or 24, eggs), we might want to round to the nearest dozen — or if we were dealing with money, we might want to round to the nearest penny (or hundredth of a dollar). On top of that, we might not actually want to round to the nearest value, but rather to the next largest value. Back to those eggs: if we computed the need for 14 eggs in a recipe, and we're trying to print a shopping list, then we don't want to round 14 eggs to the nearest one dozen, 'cause we'd come up two eggs short — instead, we want to round up to 2 dozen eggs.
So there are two ways that rounding can vary: the interval (to use a fancy mathematical term) that we're rounding to (such as integer, dozen, 0.01, etc.), and the mode (nearest, up, etc.).
Let's take the interval first, because it's the easiest to deal with. The following little function will round a given value to any interval using the given rounding function. The rounding function must round the given value to one of the adjacent integers. Notice there is some test code included that uses the rounding function built into JavaScript's standard Math class. This rounding function works exactly the same way you were taught in school:
// test our function...
gs.log(round(4, 5, Math.round));
gs.log(round(2, 5, Math.round));
gs.log(round(2.5, 5, Math.round));
gs.log(round(2.4999999, 5, Math.round));
gs.log(round(24.456, 0.01, Math.round));
gs.log(round(24.454, 0.01, Math.round));
// the generalized rounding function...
function round(value, interval, func) {
var v = value / interval;
var rv = func(v);
return rv * interval;
}
Try running this in Scripts→Background. Study the results until they make sense to you.
Now let's throw another twist into this, by using different rounding modes. In the code below, I've added a couple additional rounding mode functions and some more test code. The roundUp() function implements rounding up, as discussed above. The roundBanker() function does something a bit different, and it needs some explanation...
Way back when, somewhere in Europe a banker was computing interest on bank account balances and noticed that he was being cheated by the kind of rounding we all were taught. The problem was caused by values that were the same distance from the two nearest values they could be rounded to. For example, suppose our medieval banker was dealing with dollars and cents. He might compute the interest to be paid to a depositor as 3.565 dollars. If he's rounding to the nearest cent, using the normal rounding method, he'd round up to 3.57, because 3.565 is exactly equidistant between 3.56 and 3.57, and the rule is if halfway, round up. To the banker, that's just plain unfair! So our medieval banker came up with something called "banker's rounding" to solve the problem: when a value is exactly halfway, round to the nearest even value. By doing this, then roughly half the time you'd round up, and the other half you'd round down. The banker is now happy; the rule is fair.
Here's the code:
// test our function...
gs.log(round(4, 5, Math.round));
gs.log(round(2, 5, Math.round));
gs.log(round(2.5, 5, Math.round));
gs.log(round(2.4999999, 5, Math.round));
gs.log(round(24.456, 0.01, Math.round));
gs.log(round(24.454, 0.01, Math.round));
gs.log(round(24.001, 1, roundUp));
gs.log(round(33, 2, roundBanker));
gs.log(round(34, 2, roundBanker));
// the generalized rounding function...
function round(value, interval, func) {
var v = value / interval;
var rv = func(v);
return rv * interval;
}
// round up function
function roundUp(value) {
return Math.ceil(value);
}
// banker's rounding function
function roundBanker(value) {
var i = Math.floor(value);
var frac = value - i;
if (frac != 0.5)
return Math.round(value);
return (i & 1 == 0) ? i + 1 : i;
}
There's much more on Wikipedia.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.