Last active
April 25, 2024 19:48
-
-
Save ArcaneEngineer/44093417dc93e6a8e9ee761d2e695b06 to your computer and use it in GitHub Desktop.
Cross-platform deterministic integer division in JavaScript using a tiny WASM include
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Compile the .WAT (WebAssembly text) file to a .WASM binary, put it alongside this .js file, and you're A for Away. | |
// | |
//Goodbye to problems working with Javascript's Number, and to the indeterminism of division, remainder and rounding ops across platforms. | |
//No more need for hefty libraries like BigNumber.js, decimal.js, big.js etc. Great libraries... before WebAssembly came along :) | |
// | |
//There is some overhead to crossing the WASM/JS barrier of course. But simplicity and native performance make this more than worthwhile. | |
//At worst, you can move all your hot logic to WebAssembly to eliminate repeated call-out costs, and in that way you can also avoid | |
//any further implicit conversions to JavaScript's Number class... at least until you are ready to render the results of your computation. | |
//Just be careful how you store the values you get back, or conversion back to JS Number is on the cards. I use Int32Array to store them. | |
const wasmImportObject = { env: {} }; | |
WebAssembly.instantiateStreaming(fetch("./fixedpoint.wasm"), wasmImportObject).then((wasmResultObj) => | |
{ | |
let exports = wasmResultObj.instance.exports; | |
let dividend = BigInt(1293891283); | |
let divisor = BigInt(1879); | |
console.log( BigInt(exports.i64_div_s(dividend, divisor)) ); // signed division with pos divisor, output: 688606n | |
console.log( BigInt(exports.i64_div_u(dividend, divisor)) ); //unsigned division with pos divisor, output: 688606n | |
console.log( BigInt(exports.i64_div_s(dividend, -divisor)) ); // signed division with neg divisor, output: -688606n | |
console.log( BigInt(exports.i64_div_u(dividend, -divisor)) ); //unsigned division with neg divisor, output: 0n | |
}); | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(module | |
(type $i32_binary_op (func (param i32 i32) (result i32))) | |
(type $i64_binary_op (func (param i64 i64) (result i64))) | |
;;(type $f32_binary_op (func (param f32) (result f32))) | |
;;(type $f64_binary_op (func (param f64) (result f64))) | |
(func $i32_add (export "i32_add") (type $i32_binary_op) | |
local.get 1 | |
local.get 0 | |
i32.add) | |
(func $i32_sub (export "i32_sub") (type $i32_binary_op) | |
local.get 0 | |
local.get 1 | |
i32.sub) | |
(func $i32_mul (export "i32_mul") (type $i32_binary_op) | |
local.get 1 | |
local.get 0 | |
i32.mul) | |
(func $i32_div_s (export "i32_div_s") (type $i32_binary_op) | |
local.get 0 | |
local.get 1 | |
i32.div_s) | |
(func $i32_div_u (export "i32_div_u") (type $i32_binary_op) | |
local.get 0 | |
local.get 1 | |
i32.div_u) | |
(func $i32_rem_s (export "i32_rem_s") (type $i32_binary_op) | |
local.get 0 | |
local.get 1 | |
i32.rem_s) | |
(func $i32_rem_u (export "i32_rem_u") (type $i32_binary_op) | |
local.get 0 | |
local.get 1 | |
i32.rem_u) | |
(func $i64_add (export "i64_add") (type $i64_binary_op) | |
local.get 1 | |
local.get 0 | |
i64.add) | |
(func $i64_sub (export "i64_sub") (type $i64_binary_op) | |
local.get 0 | |
local.get 1 | |
i64.sub) | |
(func $i64_mul (export "i64_mul") (type $i64_binary_op) | |
local.get 1 | |
local.get 0 | |
i64.mul) | |
(func $i64_div_s (export "i64_div_s") (type $i64_binary_op) | |
local.get 0 | |
local.get 1 | |
i64.div_s) | |
(func $i64_div_u (export "i64_div_u") (type $i64_binary_op) | |
local.get 0 | |
local.get 1 | |
i64.div_u) | |
(func $i64_rem_s (export "i64_rem_s") (type $i64_binary_op) | |
local.get 0 | |
local.get 1 | |
i64.rem_s) | |
(func $i64_rem_u (export "i64_rem_u") (type $i64_binary_op) | |
local.get 0 | |
local.get 1 | |
i64.rem_u) | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment