Tip:
Highlight text to annotate it
X
This is Coding Maths Mini #8 - Rounding
Shout out to my British viewers who love their maths.
Today we're going to talk about rounding numbers, a subject that a lot of people take for granted,
but you can do some pretty cool things with. Rounding is simply a function that takes an
input number and gives back an output number that is either the same as, or somewhere in
the vicinity of the input. The most common type of rounding is to round to the nearest
integer. If you have 7.4 for example, you're in between the integers 7 and 8. You're closest
to 7, so that's your answer. If you were at 7.8, you'd be closer to 8 and that would be
your answer. Of course 7.5 is dead center between the two, so the convention is usually
that if the fraction is 0.5 or higher, round up, otherwise round down.
This is all stuff you should already know from grade school. But it's worth mentioning
just to make sure we're all on the same page.
Now, most programming languages have some kind of math library that usually contains
three standard rounding functions. I'll describe the JavaScript versions, but in most languages,
you'll find nearly identical functions.
Math.floor rounds down to the next lowest integer. So 7.0 will round to 7, as will 7.1,
7.5 and 7.999. If you want to see an example of Math.floor in action, check out Mini #5
on random numbers. This is usually the same thing as converting or casting a floating
point number to an integer, which usually just chops off the fractional part of the
number.
Math.ceil or ceiling does the opposite, always rounding to the next highest integer. 7.0
would still round to 7, but 7-point-anything will always round up to 8. 7.9, 7.4, 7.0001
all go to 8.
Then there's the old standard, Math.round, which rounds to the closest integer, using
the .5 and higher rule. So 7.1 would round down to 7 and 7.8 would round up to 8.
Now many programmers go along with these built in functions and do just fine, but we're going
to create a couple more rounding functions that are super powerful.
The first one allows you to round not just to integers, but to any number of decimal
places, or even to the nearest 10, 100, 1000 etc.
Now of course, when you're dealing with long floating point numbers, you often need all
those digits for accuracy in calculations. But there are plenty of times you don't need
them. Particularly when you you are displaying the value to a user. For example, if you're
making a slider control that has min and max values of 0 and 1, you probably don't need
to display the value of that slider to 10 decimal places. One or two decimals would
probably be fine.
Another obvious example is anything to do with money. Say you're doing a shopping cart
app. A user buys something for 7.99 (pounds) with a 5% VAT. Another shout out to the Brits
there. The total would be 8.3895. But you can't charge that amount. You have to round
it to the nearest cent: 8.39. Now your built in math functions don't help much because
they'll only round to the nearest integer.
So what you do is multiply by 100. This gives you 838.95. THEN you round, which gives you
839, then you divide by 100 to get 8.39.
Now, say we want to display the value of PI, which is 3.141592653589793. But you only want
to display it to 3 places. Multiply by 1000 which gives you 3141.592653589793. Round to
get 3142 and divide by 1000 to get 3.142.
If you want it to one place, multiply by 10, round, then divide by 10 and youl'll get 3.1.
So, we have 10 for one decimal place, 100 for two places, 1000 for three. Of course,
10,000 would give you four places, and so on. Now here's a trick: 10 to the power of
1 is 10, 10 to the power of 2 is 100, to the power of 3 is 1000, and 10 to the power of
4 is 10,000, and so on. This matches up perfectly to the number of places we want to round to.
So we can make a roundToPlaces function. I'll add it right to the utils library.
function roundToPlaces(value, places) { var mult = Math.pow(10, places);
return Math.round(value * mult) / mult; }
This takes the value that you want to round, and the number of places you want to round
it to. First it calculates a mult variable. This uses Math.pow to raise 10 to the specified
power. So if places is 2, we're saying Math.pow(10, 2) which is 10 to the power of 2 or 10 times
10 or 100.
Then we multiply the value by that mult variable, round it, divide it by mult and return the
result.
In this simple test file, I'm just going to log the value of PI to 1, 3, and 5 places.
And you see this gives us 3.1, 3.142, 3.14159.
An interesting thing about this function is that you can feed it negative place values
to round to powers of 10. For example, -1 will round the input value to the nearest
10, -2 to the nearest 100 and -3 to the nearest 1000. And passing in 0 simply rounds to the
nearest 1, which is the same as using Math.round directly.
Here's an example of rounding a large number to 10s, 100s and 1000s.
And here's the result.
So this function will let you round to any decimal or power of 10, but sometimes you
need to round to other values. A great example is a "snap-to-grid" function. Say you have
a 40-pixel grid and you want to snap objects so that they always align with this grid.
Well, we can just lose all the Math.pow stuff and switch the order of things around to create
a roundNearest function.
function roundNearest(value, nearest) { return Math.round(value / nearest) * nearest;
So in the grid example, say the current value was 113 and we want to round that to the nearest
}
multiple of 40 to align with the grid. We divide value, 113, by 40 and we get 2.825.
Rounded, is 3. Multiply 3 by 40 to get 120. And that's the multiple of 40 that's closest
to 113.
Here's an example file. I set a gridSize of 40 pixels. Then I listen for mousemove to
get the current mouse coordinates. I draw a grid using this drawGrid function which
just draws a bunch of horizontal and vertical lines spaced using gridSize. Then I use roundNearest(event.clientX,
gridSize) to get a rounded x value and I do the same with clientY to get a rounded y value.
Finally I just draw a circle at that x, y position.
We run that...
and see that no matter where I move the mouse, it draws a circle centered on one of the grid
coordinates. Try changing gridSize and you'll see the new grid drawn to that size and the
circle will still automatically snap to that new grid.
So a couple of new utility functions. I'm sure you'll find these very useful. See you
next time.