BIT-101
Bill Gates touched my MacBook Pro
Rounding floating point numbers is a pretty common need. Occasionally needed in calculations, but way more common in displaying numbers. You don’t want to be telling someone that two locations are 7.394739782 miles apart. 7.4 is probably fine. And 7.39 will satisfy most anyone. So let’s make a function that will let you round to any level of precision.
Rounding a floating point number to a whole number is generally built in to most math libraries. We’ll use the magic number 3.14159 for our examples.
round(3.14159) // 3.0
If you want to round to one decimal place:
For two decimal places:
And so on. Multiply and divide by 1000 to get 3.142 (the final 1 gets rounded up to 2).
So, if we want to be able to round to an arbitrary number of decimal places, we need to be able to equate:
The function is pow
. It’s in most math libraries and raised a number to a certain power. So we can say:
pow(10, 1) // 10
pow(10, 2) // 100
pow(10, 3) // 1000
// etc.
In fact, pow(10, 0)
equals 1. This means multiply by 1, round, divide by 1, which is the same as just rounding to zero decimal places.
Since we’ll be using the value twice, we might as well store it. So we get:
function roundTo(val, places) {
mult = pow(10, places)
val = val * mult
val = round(val)
val = val / mult
return val
}
I wrote it out line by line for clarity, but you can shorten this to:
function roundTo(val, places) {
mult = pow(10, places)
return round(val * mult) / mult
}
And testing this…
roundTo(3.14159, 0) // 3.0
roundTo(3.14159, 1) // 3.1
roundTo(3.14159, 2) // 3.14
roundTo(3.14159, 3) // 3.142
There’s another bit of magic here though. It works with negative numbers too!
It happens that pow(10, -1)
is 0.1. Take a number like 6789 and multiply by 0.1 and you get 678.9. Round it to 679 and divide by 0.1 to get 6790. You just rounded to the nearest tens place. So…
roundTo(6789, -1) // 6790
roundTo(6789, -2) // 6800
roundTo(6789, -3) // 7000
Since that one was pretty easy, here’s a related one. Say instead of rounding to the nearest power of ten, you wanted to round to the nearest multiple of a number.
For example:
7 rounded to the nearest 3 would be 6. 8 rounded to the nearest 3 would be 9. 7 rounded to the nearest 4 would be 8.
This one is even simpler to code than roundTo
:
function roundToNearest(val, mult) {
return round(val / mult) * mult
}
And some examples:
roundNearest(7, 3) // 6
roundNearest(8, 3) // 9
roundNearest(7, 4) // 8
You might wonder when you’d need something like this. It’s good for quantizing values, or creating stairstepping kind of functions. Say I’m plotting values across a 400x400 pixel canvas with x going from 0 to the width of the canvas. And y will be the height of the canvas minus x.
for (x = 0; x < width; x += 5) {
y = height - x
circle(x, y, 2)
}
This gets us something like this:
Now let’s quantize the y value so it’s always a multiple of 40.
for (x = 0; x < width; x += 5) {
y = height - x
y = roundNearest(y, 40)
circle(x, y, 2)
}
The result:
An even more useful example would be quantizing the colors of an image. Say each channel of each pixel had a value from 0 to 255. You could say:
value = roundNearest(value, 64)
Now each value would be 0, 64, 128, 192 or 256. You’d have to clamp
that last value to have it equal 255. Now you’ve reduced the values from 256 to 5. It might not be the best way to go about this, but it should give you an idea of how you can apply the function.
Comments? Best way to shout at me is on Mastodon