From d66f9d205c25c735928a17f4f2ee1f0957545e88 Mon Sep 17 00:00:00 2001 From: Max Graey Date: Sun, 15 Apr 2018 01:35:43 +0300 Subject: [PATCH] Add portable ctz, popcnt, rotl, rotr, nearest & copysign (#75) Thank you! --- std/portable.d.ts | 12 ++++++++++++ std/portable.js | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/std/portable.d.ts b/std/portable.d.ts index 68f8ffd6..c88dac4b 100644 --- a/std/portable.d.ts +++ b/std/portable.d.ts @@ -135,16 +135,28 @@ declare namespace f64 { /** Performs the sign-agnostic count leading zero bits operation on a 32-bit integer. All zero bits are considered leading if the value is zero. */ declare function clz(value: T): T; +/** Performs the sign-agnostic count tailing zero bits operation on a 32-bit integer. All zero bits are considered trailing if the value is zero. */ +declare function ctz(value: T): T; +/** Performs the sign-agnostic count number of one bits operation on a 32-bit integer. */ +declare function popcnt(value: T): T; +/** Performs the sign-agnostic rotate left operation on a 32-bit integer. */ +declare function rotl(value: T, shift: T): T; +/** Performs the sign-agnostic rotate right operation on a 32-bit integer. */ +declare function rotr(value: T, shift: T): T; /** Computes the absolute value of an integer or float. */ declare function abs(value: T): T; /** Determines the maximum of two integers or floats. If either operand is `NaN`, returns `NaN`. */ declare function max(left: T, right: T): T; /** Determines the minimum of two integers or floats. If either operand is `NaN`, returns `NaN`. */ declare function min(left: T, right: T): T; +/** Composes a 32-bit or 64-bit float from the magnitude of `x` and the sign of `y`. */ +declare function copysign(x: T, y: T): T; /** Performs the ceiling operation on a 32-bit or 64-bit float. */ declare function ceil(value: T): T; /** Performs the floor operation on a 32-bit or 64-bit float. */ declare function floor(value: T): T; +/** Rounds to the nearest integer tied to even of a 32-bit or 64-bit float. */ +declare function nearest(value: T): T; /** Selects one of two pre-evaluated values depending on the condition. */ declare function select(ifTrue: T, ifFalse: T, condition: bool): T; /** Calculates the square root of a 32-bit or 64-bit float. */ diff --git a/std/portable.js b/std/portable.js index c0c565ac..96a413aa 100644 --- a/std/portable.js +++ b/std/portable.js @@ -75,6 +75,27 @@ Object.defineProperties( globalScope["clz"] = Math.clz32; +globalScope["ctz"] = function ctz(value) { + var c = Math.clz32(value & -value); + return value ? 31 - c : c; +}; + +globalScope["popcnt"] = function popcnt(value) { + value -= value >>> 1 & 0x55555555; + value = (value & 0x33333333) + (value >>> 2 & 0x33333333); + return (((value + (value >>> 4)) & 0x0F0F0F0F) * 0x01010101) >>> 24; +}; + +globalScope["rotl"] = function rotl(value, shift) { + shift &= 31; + return (value << shift) | (value >>> (32 - shift)); +}; + +globalScope["rotr"] = function rotr(value, shift) { + shift &= 31; + return (value >>> shift) | (value << (32 - shift)); +}; + globalScope["abs"] = Math.abs; globalScope["max"] = Math.max; @@ -85,6 +106,14 @@ globalScope["ceil"] = Math.ceil; globalScope["floor"] = Math.floor; +// Adopt code from https://github.com/rfk/wasm-polyfill +globalScope["nearest"] = function nearest(value) { + if (Math.abs(value - Math.trunc(value)) === 0.5) { + return 2.0 * Math.round(value * 0.5); + } + return Math.round(value); +}; + globalScope["select"] = function select(ifTrue, ifFalse, condition) { return condition ? ifTrue : ifFalse; }; @@ -93,6 +122,10 @@ globalScope["sqrt"] = Math.sqrt; globalScope["trunc"] = Math.trunc; +globalScope["copysign"] = function copysign(x, y) { + return Math.abs(x) * Math.sign(y); +}; + globalScope["bswap"] = function bswap(value) { var a = value >> 8 & 0x00FF00FF; var b = (value & 0x00FF00FF) << 8;