Move fmod/fmodf to builtins and bind them to the '%' operator

This commit is contained in:
dcodeIO
2018-03-24 18:39:20 +01:00
parent 721d77012b
commit c80bf35747
21 changed files with 4378 additions and 4209 deletions

4
std/assembly.d.ts vendored
View File

@ -249,6 +249,10 @@ declare function parseI32(str: string, radix?: i32): i32;
declare function parseI64(str: string, radix?: i32): i64;
/** Parses a string to a 64-bit float. */
declare function parseFloat(str: string): f64;
/** Returns the 64-bit floating-point remainder of `x/y`. */
declare function fmod(x: f64, y: f64): f64;
/** Returns the 32-bit floating-point remainder of `x/y`. */
declare function fmodf(x: f32, y: f32): f32;
// Standard library

View File

@ -172,3 +172,123 @@ export namespace f64 {
export declare const HEAP_BASE: usize;
export declare function start(): void;
export function fmod(x: f64, y: f64): f64 {
// based on musl's implementation of fmod
var ux = reinterpret<u64>(x);
var uy = reinterpret<u64>(y);
var ex = <i32>(ux >> 52 & 0x7ff);
var ey = <i32>(uy >> 52 & 0x7ff);
var sx = <i32>(ux >> 63);
if (uy << 1 == 0 || isNaN<f64>(y) || ex == 0x7ff) {
return (x * y) / (x * y);
}
if (ux << 1 <= uy << 1) {
if (ux << 1 == uy << 1) return 0 * x;
return x;
}
// normalize x and y
var i: u64;
if (!ex) {
for (i = ux << 12; !(i >> 63); i <<= 1) --ex;
ux <<= -ex + 1;
} else {
ux &= <u64>-1 >> 12;
ux |= 1 << 52;
}
if (!ey) {
for (i = uy << 12; !(i >> 63); i <<= 1) --ey;
uy <<= -ey + 1;
} else {
uy &= <u64>-1 >> 12;
uy |= 1 << 52;
}
// x mod y
for (; ex > ey; ex--) {
i = ux - uy;
if (!(i >> 63)) {
if (!i) return 0 * x;
ux = i;
}
ux <<= 1;
}
i = ux - uy;
if (!(i >> 63)) {
if (!i) return 0 * x;
ux = i;
}
for (; !(ux >> 52); ux <<= 1) --ex;
// scale result
if (ex > 0) {
ux -= 1 << 52;
ux |= <u64>ex << 52;
} else {
ux >>= -ex + 1;
}
ux |= <u64>sx << 63;
return reinterpret<f64>(ux);
}
export function fmodf(x: f32, y: f32): f32 {
// based on musl's implementation of fmodf
var ux = reinterpret<u32>(x);
var uy = reinterpret<u32>(y);
var ex = <i32>(ux >> 23 & 0xff);
var ey = <i32>(uy >> 23 & 0xff);
var sx = ux & 0x80000000;
if (uy << 1 == 0 || isNaN<f32>(y) || ex == 0xff) {
return (x * y) / (x * y);
}
if (ux << 1 <= uy << 1) {
if (ux << 1 == uy << 1) return 0 * x;
return x;
}
// normalize x and y
var i: u32;
if (!ex) {
for (i = ux << 9; !(i >> 31); i <<= 1) --ex;
ux <<= -ex + 1;
} else {
ux &= <u32>-1 >> 9;
ux |= 1 << 23;
}
if (!ey) {
for (i = uy << 9; !(i >> 31); i <<= 1) --ey;
uy <<= -ey + 1;
} else {
uy &= <u32>-1 >> 9;
uy |= 1 << 23;
}
// x mod y
for (; ex > ey; --ex) {
i = ux - uy;
if (!(i >> 31)) {
if (!i) return 0 * x;
ux = i;
}
ux <<= 1;
}
i = ux - uy;
if (!(i >> 31)) {
if (!i) return 0 * x;
ux = i;
}
for (; !(ux >> 23); ux <<= 1) --ex;
// scale result
if (ex > 0) {
ux -= 1 << 23;
ux |= <u32>ex << 23;
} else {
ux >>= -ex + 1;
}
ux |= sx;
return reinterpret<f32>(ux);
}

95
std/portable.d.ts vendored
View File

@ -193,6 +193,10 @@ declare function parseInt(str: string, radix?: i32): f64;
declare function parseI32(str: string, radix?: i32): i32;
/** Parses a floating point string to a 64-bit float. */
declare function parseFloat(str: string): f64;
/** Returns the 64-bit floating-point remainder of `x/y`. */
declare function fmod(x: f64, y: f64): f64;
/** Returns the 32-bit floating-point remainder of `x/y`. */
declare function fmodf(x: f32, y: f32): f32;
// Portable standard library
// Everything marked @deprecated is a temporary filler. Do not use.
@ -310,52 +314,55 @@ interface Iterable<T> {
interface Iterator<T> {}
declare namespace Math {
export const E: f64;
export const LN2: f64;
export const LN10: f64;
export const LOG2E: f64;
export const LOG10E: f64;
export const PI: f64;
export const SQRT1_2: f64;
export const SQRT2: f64;
export function abs(x: f64): f64;
export function acos(x: f64): f64;
export function acosh(x: f64): f64;
export function asin(x: f64): f64;
export function asinh(x: f64): f64;
export function atan(x: f64): f64;
export function atan2(y: f64, x: f64): f64;
export function atanh(x: f64): f64;
export function cbrt(x: f64): f64;
export function ceil(x: f64): f64;
export function clz32(x: f64): i32;
export function cos(x: f64): f64;
export function cosh(x: f64): f64;
export function exp(x: f64): f64;
export function expm1(x: f64): f64;
export function floor(x: f64): f64;
export function fround(x: f64): f32;
export function hypot(value1: f64, value2: f64): f64; // TODO: see std/math
export function imul(a: f64, b: f64): i32;
export function log(x: f64): f64;
export function log10(x: f64): f64;
export function log1p(x: f64): f64;
export function log2(x: f64): f64;
export function max(value1: f64, value2: f64): f64; // TODO: see std/math
export function min(value1: f64, value2: f64): f64; // TODO: see std/math
export function pow(base: f64, exponent: f64): f64;
export function random(): f64;
export function round(x: f64): f64;
export function sign(x: f64): f64;
export function sin(x: f64): f64;
export function sinh(x: f64): f64;
export function sqrt(x: f64): f64;
export function tan(x: f64): f64;
export function tanh(x: f64): f64;
export function trunc(x: f64): f64;
interface IMath {
readonly E: f64;
readonly LN2: f64;
readonly LN10: f64;
readonly LOG2E: f64;
readonly LOG10E: f64;
readonly PI: f64;
readonly SQRT1_2: f64;
readonly SQRT2: f64;
abs(x: f64): f64;
acos(x: f64): f64;
acosh(x: f64): f64;
asin(x: f64): f64;
asinh(x: f64): f64;
atan(x: f64): f64;
atan2(y: f64, x: f64): f64;
atanh(x: f64): f64;
cbrt(x: f64): f64;
ceil(x: f64): f64;
clz32(x: f64): i32;
cos(x: f64): f64;
cosh(x: f64): f64;
exp(x: f64): f64;
expm1(x: f64): f64;
floor(x: f64): f64;
fround(x: f64): f32;
hypot(value1: f64, value2: f64): f64; // TODO: see std/math
imul(a: f64, b: f64): i32;
log(x: f64): f64;
log10(x: f64): f64;
log1p(x: f64): f64;
log2(x: f64): f64;
max(value1: f64, value2: f64): f64; // TODO: see std/math
min(value1: f64, value2: f64): f64; // TODO: see std/math
pow(base: f64, exponent: f64): f64;
random(): f64;
round(x: f64): f64;
sign(x: f64): f64;
sin(x: f64): f64;
sinh(x: f64): f64;
sqrt(x: f64): f64;
tan(x: f64): f64;
tanh(x: f64): f64;
trunc(x: f64): f64;
}
declare const Math: IMath;
declare const JSMath: IMath;
declare namespace console {
/** @deprecated */
function log(message: string): void;

View File

@ -169,4 +169,13 @@ globalScope["isString"] = function isString(arg) {
globalScope["isArray"] = Array.isArray;
require("./portable/memory");
globalScope["fmod"] = function fmod(x, y) {
return x % y;
};
globalScope["fmodf"] = function fmodf(x, y) {
return Math.fround(x % y);
};
require("./portable/math")(globalScope);
require("./portable/memory")(globalScope);

3
std/portable/math.js Normal file
View File

@ -0,0 +1,3 @@
module.exports = globalScope => {
globalScope["JSMath"] = Math;
};

View File

@ -1,38 +1,38 @@
var globalScope = typeof window !== "undefined" && window || typeof global !== "undefined" && global || self;
module.exports = globalScope => {
var HEAP = new Uint8Array(0);
var HEAP_OFFSET = 0;
var HEAP = new Uint8Array(0);
var HEAP_OFFSET = 0;
globalScope["allocate_memory"] = function allocate_memory(size) {
if (!(size >>>= 0))
return 0;
if (HEAP_OFFSET + size > HEAP.length) {
var oldHeap = HEAP;
HEAP = new Uint8Array(Math.max(65536, HEAP.length + size, HEAP.length * 2));
HEAP.set(oldHeap);
}
var ptr = HEAP_OFFSET;
if ((HEAP_OFFSET += size) & 7)
HEAP_OFFSET = (HEAP_OFFSET | 7) + 1;
return ptr;
};
globalScope["allocate_memory"] = function allocate_memory(size) {
if (!(size >>>= 0))
return 0;
if (HEAP_OFFSET + size > HEAP.length) {
var oldHeap = HEAP;
HEAP = new Uint8Array(Math.max(65536, HEAP.length + size, HEAP.length * 2));
HEAP.set(oldHeap);
}
var ptr = HEAP_OFFSET;
if ((HEAP_OFFSET += size) & 7)
HEAP_OFFSET = (HEAP_OFFSET | 7) + 1;
return ptr;
};
globalScope["free_memory"] = function free_memory(ptr) {
// TODO
};
globalScope["move_memory"] = function move_memory(dest, src, n) {
HEAP.copyWithin(dest, src, src + n);
};
globalScope["store"] = function store(ptr, val, off) {
if (typeof off === "number")
ptr += off;
HEAP[ptr] = val;
};
globalScope["load"] = function load(ptr) {
if (typeof off === "number")
ptr += off;
return HEAP[ptr];
globalScope["free_memory"] = function free_memory(ptr) {
// TODO
};
globalScope["move_memory"] = function move_memory(dest, src, n) {
HEAP.copyWithin(dest, src, src + n);
};
globalScope["store"] = function store(ptr, val, off) {
if (typeof off === "number")
ptr += off;
HEAP[ptr] = val;
};
globalScope["load"] = function load(ptr) {
if (typeof off === "number")
ptr += off;
return HEAP[ptr];
};
};