Skip to content

Instantly share code, notes, and snippets.

@ArcaneEngineer
Last active April 25, 2024 19:48
Show Gist options
  • Save ArcaneEngineer/44093417dc93e6a8e9ee761d2e695b06 to your computer and use it in GitHub Desktop.
Save ArcaneEngineer/44093417dc93e6a8e9ee761d2e695b06 to your computer and use it in GitHub Desktop.
Cross-platform deterministic integer division in JavaScript using a tiny WASM include
//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
});
(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