Alok Menghrajani
Currently: security consulting and lecturer.
Previously: security engineering at Square Block. Co-author of Hack (the programming language) and put the 's' in https at Facebook Meta. Maker of various CTF puzzles.
This blog does not use any tracking cookies and does not serve any ads. Enjoy your anonymity; I have no idea who you are, where you came from, and where you are headed to. Keep the dream of an Internet from times past alive.
Home | Contact me | Github | RSS feed | Consulting services | Tools & games
There are several common ways to round numbers. This post explains some of these rounding methods, what to do when a rounding method isn’t available, and an analysis of rounding behavior across different version of Java.
Common rounding methods include floor (round down), ceil (round up), truncate (round towards zero), banker’s rounding, etc. Usually you can use all these different rounding methods out of the box.
Example: floor rounds numbers down. This means floor(2.7) is 2 and floor(-2.7) is -3.
You might come across cases where rounding towards the nearest
half mark (i.e. rounding towards the nearest 0.5) is missing. As a work around, you can double the value and then half the result of rounding. I.e. round_to_closest_half(x) = round(x*2)/2.
It is however important to keep in mind that floating point computations have tricky edge cases. A naive rounding implementation can therefore hide bugs.
For example, Java 6 implemented rounding as floor(x+0.5), which causes it to return an incorrect value for 0.49999999999999994. The reason is that
adding 0.5 to 0.49999999999999994 cannot be accurately represented as a floating point. The addition is approximate and the result is rounded to 1. Perhaps they should have implemented rounding as floor(x-0.5)+1?
Java 7 changed the rounding logic and updated the documentation accordingly
The story doesn’t end here and the implementation of rounding had to be changed again.
One way to discover such edge cases is to re-implement the floating point library as a tiny float (e.g. with 8-bit instead of 64-bit) and then check every possible value, something I discuss in a PagedOut! #7 article.