Get next smallest nearest number to a decimal
I tried to implement Pointy's suggestion from the comments (using typed arrays). This is loosely adapted from glibc's implementation of nextafter
. Should be good enough.
You can actually just increment/decrement the 64-bit integer representation of a double to get the wanted result. A mantissa overflow will overflow to the exponent which happens to be just what you want.
Since JavaScript doesn't provide a Uint64Array
I had to implement a manual overflow over two 32-bit integers.
This works on little-endian architectures, but I've left out big-endian since I have no way to test it. If you need this to work on big-endian architectures you'll have to adapt this code.
// Return the next representable double from value towards direction
function nextNearest(value, direction) {
if (typeof value != "number" || typeof direction != "number")
return NaN;
if (isNaN(value) || isNaN(direction))
return NaN;
if (!isFinite(value))
return value;
if (value === direction)
return value;
var buffer = new ArrayBuffer(8);
var f64 = new Float64Array(buffer);
var u32 = new Uint32Array(buffer);
f64[0] = value;
if (value === 0) {
u32[0] = 1;
u32[1] = direction < 0 ? 1 << 31 : 0;
} else if ((value > 0) && (value < direction) || (value < 0) && (value > direction)) {
if (u32[0]++ === 0xFFFFFFFF)
u32[1]++;
} else {
if (u32[0]-- === 0)
u32[1]--;
}
return f64[0];
}
var testCases = [0, 1, -1, 0.1,
-1, 10, 42e42,
0.9999999999999999, 1.0000000000000002,
10.00000762939453, // overflows between dwords
5e-324, -5e-324, // minimum subnormals (around zero)
Number.MAX_VALUE, -Number.MAX_VALUE,
Infinity, -Infinity, NaN];
document.write("<table><tr><th>n</th><th>next</th><th>prev</th></tr>");
testCases.forEach(function(n) {
var next = nextNearest(n, Infinity);
var prev = nextNearest(n, -Infinity);
document.write("<tr><td>" + n + "</td><td>" + next + "</td><td>" + prev + "</td></tr>");
});
document.write("</table>");