Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fast nextafter function in JavaScript

I'm trying to iterate through all 32 bit floating point numbers in JavaScript to visually compare some methods for polynomial evaluation for accuracy. To do so, I've implemented the code shown below. Unfortunately, this code is way too slow.

Would there be any way to improve performance?

In C/C++ the equivalent code runs in a bit over a minute on my computer, whereas I haven't had the patience to see how long this code takes.

function nextFloat(f) {
    // Note that this moves away from 0.0
    // It will fail at +/- infinity and result in an NaN
    var bitRepr = floatToBits(f);
    bitRepr++;
    return bitsToFloat(bitRepr);
}

function prevFloat(f) {
    // Note that this moves towards 0.0
    // This will fail at 0.0 and result in an NaN
    var bitRepr = floatToBits(f);
    bitRepr--;
    return bitsToFloat(bitRepr);
}

function floatToBits(f) {
    var buf = new ArrayBuffer(4);
    (new Float32Array(buf))[0] = f;
    return (new Uint32Array(buf))[0];
}

function bitsToFloat(b) {
    var buf = new ArrayBuffer(4);
    (new Uint32Array(buf))[0] = b;
    return (new Float32Array(buf))[0];
}

Another method I might consider is using is multiplying the number by (1 + epsilon), though I believe that has edge cases that I would need to resolve at the bit level anyways.

like image 452
mfdeakin Avatar asked Aug 10 '15 17:08

mfdeakin


2 Answers

If your code is synchronous you don't need to be calling new all the time, this means that you can keep your Uint32Array and Float32Array which are linked through the same buffer across all functions, for example

var obj = (function () {
    var int = new Uint32Array(1),
        float = new Float32Array(int.buffer);
    return {
        i2f: function (i) {
            int[0] = i;
            return float[0];
        },
        f2i: function (f) {
            float[0] = f;
            return int[0];
        },
        next: function () {
            int[0] = int[0] + 1;
            return float[0];
        },
        prev: function () {
            int[0] = int[0] - 1;
            return float[0];
        }
    };
}());
like image 185
Paul S. Avatar answered Oct 23 '22 04:10

Paul S.


Something like this should work, and doesn't require allocating arrays:

function testall(f) {
    var M = Math.pow(2,-126);
    var x;
    for (p = -1; p <= 1; p +=2) {
        for (s = 0; s < 1<<23; s++) {
            // subnormals (including zeros)
            x = p*M*(s/(1<<23));
            f(x);
        }
        for (b = M; b <= 2/M; b *= 2) {
            for (s = 0; s < 1<<23; s++) {
                // normals
                x = p*b*(1+s/(1<<23));
                f(x);
            }
        }
    }
}

This will iterate through all real-valued floats (subnormals and normals). It won't handle Infs (there are only two of those, so I leave them up to you), or NaNs (as far as I know, there is no efficient way to iterate through all the NaN bit patterns in JavaScript).

like image 22
Simon Byrne Avatar answered Oct 23 '22 04:10

Simon Byrne