Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Thanks! Also: this library has been Atwood's Law-ed #4

Open
JobLeonard opened this issue Mar 7, 2018 · 2 comments
Open

Thanks! Also: this library has been Atwood's Law-ed #4

JobLeonard opened this issue Mar 7, 2018 · 2 comments

Comments

@JobLeonard
Copy link

So I'm building an SPA for biologists that has dynamic plots, and I have a ton of typed arrays that often need log2 projections.

Guess what, your approximation works in JavaScript!

You see, while JavaScript officially only has doubles for numbers, and does not support unions, there is a workaround: using the shared backing buffers of TypedArrays. In other words: we create a one element Float32Array, use the same backing buffer for a Uint32Array, and voila, we have our union:

// Fake a C-union using a typed array
const unionU32 = new Uint32Array(1),
    unionF32 = new Float32Array(unionU32.buffer);

function fastlog2(x) {
    unionF32[0] = x;
    let vx_u = unionU32[0];
    unionU32[0] = (vx_u & 0x007FFFFF) | 0x3F000000;
    let mx_f = unionF32[0];
    return (vx_u * 1.1920928955078125e-7) - 124.22551499 - 1.498030302 * mx_f - 1.72587999 / (0.3520887068 + mx_f);
}

/**
 * Make use of the backingbuffer to convert using the same backing array
 * (should give better cache locality).
 * For small arrays the construction of a Uint32Array is slower, but for 
 * larger arrays (the main use-case for this function) this ekes out up to 20% extra performance
 * @param {Float32Array} n
 */
export function fasterlogF32Array(n) {
	for (let i = 0, nU32 = new Uint32Array(n.buffer); i < n.length; i++) {
		n[i] = (nU32[i] * 8.262958288192749e-8) - 87.98997108857598;
	}
	return n;
}

Yes, I know this is perverted. But hey, it works! No asm.js or WASM required! And it's fast! Only the desktop of chrome Chrome does not have an immediate disadvantage (and even then only since the last couple of versions - TypedArrays have been given the shaft in terms of optimisations for years). In all other browsers (Firefox, Edge, and all mobile browsers I tried out) seem to benefit from it:

https://run.perf.zone/view/Paul-Mineros-fastlog2-fasterlog2-Float32Array-versions-array-of-100000-elements-v4-1520435680338

https://run.perf.zone/view/Paul-Mineros-fastlog2-fasterlog2-Float32Array-versions-array-of-100-elements-v4-1520436338346

@JobLeonard
Copy link
Author

I haven't had a need for the other functions yet, so I haven't ported them. Maybe I should, and create an NPM module.

Anyway, thanks again for the library!

@JobLeonard
Copy link
Author

Ok so I have a question after all! Since all floating point operations in JS use doubles (and I just checked - making the literals fit in a float32 doesn't affect anything), could I gain some extra accuracy by having the constants calculated to the highest precision available to doubles? Since that could reduce rounding errors in intermediate calculations, right?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant