mirror of https://github.com/svaarala/duktape.git
Browse Source
This avoids the need for a function call and up to two property lookups for a `Math.pow()` invocation, as well as allowing expressions like `2 ** 16` to be inlined at compile time. Exponentiation uses the same internal handler as `Math.pow()`, per the ES7 specification. Usage: x = base ** exp; x **= 2;pull/987/head
Bruce Pascoe
8 years ago
10 changed files with 180 additions and 115 deletions
@ -0,0 +1,70 @@ |
|||||
|
/*
|
||||
|
* Shared helpers for arithmetic operations |
||||
|
*/ |
||||
|
|
||||
|
#include "duk_internal.h" |
||||
|
|
||||
|
/* Shared helper for Math.pow() and exponentiation operator */ |
||||
|
DUK_INTERNAL double duk_js_arith_pow(double x, double y) { |
||||
|
/* The ANSI C pow() semantics differ from Ecmascript.
|
||||
|
* |
||||
|
* E.g. when x==1 and y is +/- infinite, the Ecmascript required |
||||
|
* result is NaN, while at least Linux pow() returns 1. |
||||
|
*/ |
||||
|
|
||||
|
duk_small_int_t cx, cy, sx; |
||||
|
|
||||
|
DUK_UNREF(cx); |
||||
|
DUK_UNREF(sx); |
||||
|
cy = (duk_small_int_t) DUK_FPCLASSIFY(y); |
||||
|
|
||||
|
if (cy == DUK_FP_NAN) { |
||||
|
goto ret_nan; |
||||
|
} |
||||
|
if (DUK_FABS(x) == 1.0 && cy == DUK_FP_INFINITE) { |
||||
|
goto ret_nan; |
||||
|
} |
||||
|
#if defined(DUK_USE_POW_NETBSD_WORKAROUND) |
||||
|
/* See test-bug-netbsd-math-pow.js: NetBSD 6.0 on x86 (at least) does not
|
||||
|
* correctly handle some cases where x=+/-0. Specific fixes to these |
||||
|
* here. |
||||
|
*/ |
||||
|
cx = (duk_small_int_t) DUK_FPCLASSIFY(x); |
||||
|
if (cx == DUK_FP_ZERO && y < 0.0) { |
||||
|
sx = (duk_small_int_t) DUK_SIGNBIT(x); |
||||
|
if (sx == 0) { |
||||
|
/* Math.pow(+0,y) should be Infinity when y<0. NetBSD pow()
|
||||
|
* returns -Infinity instead when y is <0 and finite. The |
||||
|
* if-clause also catches y == -Infinity (which works even |
||||
|
* without the fix). |
||||
|
*/ |
||||
|
return DUK_DOUBLE_INFINITY; |
||||
|
} else { |
||||
|
/* Math.pow(-0,y) where y<0 should be:
|
||||
|
* - -Infinity if y<0 and an odd integer |
||||
|
* - Infinity otherwise |
||||
|
* NetBSD pow() returns -Infinity for all finite y<0. The |
||||
|
* if-clause also catches y == -Infinity (which works even |
||||
|
* without the fix). |
||||
|
*/ |
||||
|
|
||||
|
/* fmod() return value has same sign as input (negative) so
|
||||
|
* the result here will be in the range ]-2,0], 1 indicates |
||||
|
* odd. If x is -Infinity, NaN is returned and the odd check |
||||
|
* always concludes "not odd" which results in desired outcome. |
||||
|
*/ |
||||
|
double tmp = DUK_FMOD(y, 2); |
||||
|
if (tmp == -1.0) { |
||||
|
return -DUK_DOUBLE_INFINITY; |
||||
|
} else { |
||||
|
/* Not odd, or y == -Infinity */ |
||||
|
return DUK_DOUBLE_INFINITY; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
#endif |
||||
|
return DUK_POW(x, y); |
||||
|
|
||||
|
ret_nan: |
||||
|
return DUK_DOUBLE_NAN; |
||||
|
} |
Loading…
Reference in new issue