Getting Input To Round To Integer Value If Result Decimal Is Followed By A Series Of 9s

- 1 answer

I have a JavaScript calculator which uses the Math.cbrt() function. When I calculate the cube root of 125 it returns 4.999999999999999. I understand that I could use Math.round() to round any answers that this function returns to integer values, but I do not want to do that exactly. Is there a way to use this if and only if the result of calculation is some number followed by a string of 9s (or something similar like 4.99999998 perhaps) after the decimal?



What you are dealing with is the frustration of floating point numbers in computing. See the Floating Point Guide for more information on this critical topic.

The short version: Certain non-integer values cannot be represented accurately by computers, so they store a value that is "near enough". Just try evaluating 3.3 / 3 in your favourite REPL.

Say what?!

Computers are supposed to be perfect at this numbers/math thing, right? Can I trust any answer they give me?

Yes, for integers, they are pretty much perfect. But for non-integer calculations, you should assume that answers won't be exact, and account for these floating point errors.

The solution in Javascript

In newer versions of Javascript, you have a defined constant Number.EPSILON, which is the smallest difference between the actual number and the approximation that it can actually store.

Using this, you can multiply that constant by the result you get and add it to the result and you should get the exact value you require.

function cbrt(n) { 
    return Math.cbrt(n) + (Number.EPSILON * Math.cbrt(n)); 

Alternatively, you can use the rounding behaviour of the .toFixed() method on numbers together with the parseFloat() function if you only care about numbers up to a certain number of decimal places (less than 20).

function num(n, prec) {
    if (prec === void 0) prec = 8; // default to 8 decimal places
    return parseFloat(n.toFixed(prec));