DUK_INTERNAL duk_double_t duk_double_trunc_towards_zero(duk_double_t x) { /* XXX: optimize */ duk_small_int_t s = duk_double_signbit(x); x = DUK_FLOOR(DUK_FABS(x)); /* truncate towards zero */ if (s) { x = -x; } return x; }
/* exposed, used by e.g. duk_bi_date.c */ DUK_INTERNAL duk_double_t duk_js_tointeger_number(duk_double_t x) { duk_small_int_t c = (duk_small_int_t) DUK_FPCLASSIFY(x); if (c == DUK_FP_NAN) { return 0.0; } else if (c == DUK_FP_ZERO || c == DUK_FP_INFINITE) { /* XXX: FP_ZERO check can be removed, the else clause handles it * correctly (preserving sign). */ return x; } else { duk_small_int_t s = (duk_small_int_t) DUK_SIGNBIT(x); x = DUK_FLOOR(DUK_FABS(x)); /* truncate towards zero */ if (s) { x = -x; } return x; } }
/* combined algorithm matching E5 Sections 9.5 and 9.6 */ DUK_LOCAL duk_double_t duk__toint32_touint32_helper(duk_double_t x, duk_bool_t is_toint32) { duk_small_int_t c = (duk_small_int_t) DUK_FPCLASSIFY(x); duk_small_int_t s; if (c == DUK_FP_NAN || c == DUK_FP_ZERO || c == DUK_FP_INFINITE) { return 0.0; } /* x = sign(x) * floor(abs(x)), i.e. truncate towards zero, keep sign */ s = (duk_small_int_t) DUK_SIGNBIT(x); x = DUK_FLOOR(DUK_FABS(x)); if (s) { x = -x; } /* NOTE: fmod(x) result sign is same as sign of x, which * differs from what Javascript wants (see Section 9.6). */ x = DUK_FMOD(x, DUK_DOUBLE_2TO32); /* -> x in ]-2**32, 2**32[ */ if (x < 0.0) { x += DUK_DOUBLE_2TO32; } /* -> x in [0, 2**32[ */ if (is_toint32) { if (x >= DUK_DOUBLE_2TO31) { /* x in [2**31, 2**32[ */ x -= DUK_DOUBLE_2TO32; /* -> x in [-2**31,2**31[ */ } } return x; }
DUK_INTERNAL duk_ret_t duk_bi_math_object_hypot(duk_context *ctx) { /* * E6 Section 20.2.2.18: Math.hypot * * - If no arguments are passed, the result is +0. * - If any argument is +inf, the result is +inf. * - If any argument is -inf, the result is +inf. * - If no argument is +inf or -inf, and any argument is NaN, the result is * NaN. * - If all arguments are either +0 or -0, the result is +0. */ duk_idx_t nargs; duk_idx_t i; duk_bool_t found_nan; duk_double_t max; duk_double_t sum, summand; duk_double_t comp, prelim; duk_double_t t; nargs = duk_get_top(ctx); /* Find the highest value. Also ToNumber() coerces. */ max = 0.0; found_nan = 0; for (i = 0; i < nargs; i++) { t = DUK_FABS(duk_to_number(ctx, i)); if (DUK_FPCLASSIFY(t) == DUK_FP_NAN) { found_nan = 1; } else { max = duk_double_fmax(max, t); } } /* Early return cases. */ if (max == DUK_DOUBLE_INFINITY) { duk_push_number(ctx, DUK_DOUBLE_INFINITY); return 1; } else if (found_nan) { duk_push_number(ctx, DUK_DOUBLE_NAN); return 1; } else if (max == 0.0) { duk_push_number(ctx, 0.0); /* Otherwise we'd divide by zero. */ return 1; } /* Use Kahan summation and normalize to the highest value to minimize * floating point rounding error and avoid overflow. * * https://en.wikipedia.org/wiki/Kahan_summation_algorithm */ sum = 0.0; comp = 0.0; for (i = 0; i < nargs; i++) { t = DUK_FABS(duk_get_number(ctx, i)) / max; summand = (t * t) - comp; prelim = sum + summand; comp = (prelim - sum) - summand; sum = prelim; } duk_push_number(ctx, (duk_double_t) DUK_SQRT(sum) * max); return 1; }
DUK_LOCAL double duk__fabs(double x) { return DUK_FABS(x); }
static double duk__pow_fixed(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. */ int cx, cy, sx; DUK_UNREF(cx); DUK_UNREF(sx); cy = 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_FPCLASSIFY(x); if (cx == DUK_FP_ZERO && y < 0.0) { sx = 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; }