The brief version of my question is:
What's considered "best practice" for deciding when a floating point number
x
andMath.round(x)
may be considered equal, allowing for loss of precision from floating-point operations?
The long-winded version is:
I often need to decide whether or not a given floating point value x
should be "regarded as an integer", or more pedantically, should be "regarded as the floating point representation of an integer".
(For example, if n is an integer, the mathematical expression
log10(10n)
is a convoluted way of representing the same integer n. This is the thinking that motivates saying that the result of the analogous floating-point computation may be regarded as "the representation of an integer".)
The decision is easy whenever Math.round(x) == x
evaluates to true
: in this case we can say that x
is indeed (the floating point representation of) an integer.
But the test Math.round(x) == x
is inconclusive when it evaluates to false
. For example,
function log10(x) { return Math.log(x)/Math.LN10; }
// -> function()
x = log10(Math.pow(10, -4))
// -> -3.999999999999999
Math.round(x) == x
// -> false
EDIT: one "solution" I often see is to pick some arbitrary tolerance, like ε = 1e-6
, and test for Math.abs(Math.round(x) - x) < ε
. I think such solutions would produce more false positives than I'd find acceptable.