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?

- 251
- 3
- 17
-
Literally only if it's all 9's? What about `4.9999999998`? – Mike Cluck Jan 13 '16 at 02:12
-
@MikeC Edited in response to your comment. – newbie2015 Jan 13 '16 at 02:14
-
Wouldn't you want the same thing also for rounding down? – Thilo Jan 13 '16 at 02:21
-
see related [How to deal with overflow and underflow?](http://stackoverflow.com/a/33006665/2521214). you can detect the overflow/underflow by inspecting the mantisa binary representation directly ... and also directly correct it ... – Spektre Jan 13 '16 at 08:20
2 Answers
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));
}

- 37,147
- 8
- 62
- 67
-
How might I use Number.EPSILON with a trig function? I tried adding it but that only works for some arguments. Others it needs to be subtracted to give the exact value. Is there a way to check if the result is just over/under the exact value? – newbie2015 Jan 15 '16 at 09:32
-
@newbie2015 I'm not sure, to be honest, I am still trying to figure out if there is one silver bullet approach to deal with all floating point inaccuracies in JS. Perhaps it only works reliably for cube roots because the answer will always be the same sign as the input, whereas that isn't true for trig functions. Have you tried to the `parseFloat(x.toFixed(n))` approach instead? – GregL Jan 17 '16 at 23:37
-
I haven't, no. I'm not the sharpest with JavaScript so I'm not sure exactly how to get it to work with something like a trig function. My calculator uses the function function `tan(form) { form.display.value = Math.tan(form.display.value); }` How might this look if we included the `parseFloat(x.toFixed(n))` bit? – newbie2015 Jan 18 '16 at 01:50
-
1@newbie2015 I would just create a global helper function like the `num` function at the end of my answer, and then your function would just use it: `function tan(form) { form.display.value = num(Math.tan(form.display.value)); }`. – GregL Jan 18 '16 at 02:09
var threshold = 0.999; // set to whatever you want
var fraction = result % 1;
if (fraction >= threshold) {
result = Math.round(result);
}

- 31,869
- 13
- 80
- 91
-
@Thilo This will only round up to integers. If it needs to do more then OP needs to specify. – Mike Cluck Jan 13 '16 at 02:29