text: /*
   *  Shared helpers for arithmetic operations
   */
  
  #include "duk_internal.h"
  
  /* ECMAScript modulus ('%') does not match IEEE 754 "remainder" operation
   * (implemented by remainder() in C99) but does seem to match ANSI C fmod().
   * Compare E5 Section 11.5.3 and "man fmod".
   */
  DUK_INTERNAL double duk_js_arith_mod(double d1, double d2) {
  #if defined(DUK_USE_POW_WORKAROUNDS)
  	/* Specific fixes to common fmod() implementation issues:
  	 * - test-bug-mingw-math-issues.js
  	 */
  	if (DUK_ISINF(d2)) {
  		if (DUK_ISINF(d1)) {
  			return DUK_DOUBLE_NAN;
  		} else {
  			return d1;
  		}
  	} else if (duk_double_equals(d1, 0.0)) {
  		/* d1 +/-0 is returned as is (preserving sign) except when
  		 * d2 is zero or NaN.
  		 */
  		if (duk_double_equals(d2, 0.0) || DUK_ISNAN(d2)) {
  			return DUK_DOUBLE_NAN;
  		} else {
  			return d1;
  		}
  	}
  #else
  	/* Some ISO C assumptions. */
  	DUK_ASSERT(duk_double_equals(DUK_FMOD(1.0, DUK_DOUBLE_INFINITY), 1.0));
  	DUK_ASSERT(duk_double_equals(DUK_FMOD(-1.0, DUK_DOUBLE_INFINITY), -1.0));
  	DUK_ASSERT(duk_double_equals(DUK_FMOD(1.0, -DUK_DOUBLE_INFINITY), 1.0));
  	DUK_ASSERT(duk_double_equals(DUK_FMOD(-1.0, -DUK_DOUBLE_INFINITY), -1.0));
  	DUK_ASSERT(DUK_ISNAN(DUK_FMOD(DUK_DOUBLE_INFINITY, DUK_DOUBLE_INFINITY)));
  	DUK_ASSERT(DUK_ISNAN(DUK_FMOD(DUK_DOUBLE_INFINITY, -DUK_DOUBLE_INFINITY)));
  	DUK_ASSERT(DUK_ISNAN(DUK_FMOD(-DUK_DOUBLE_INFINITY, DUK_DOUBLE_INFINITY)));
  	DUK_ASSERT(DUK_ISNAN(DUK_FMOD(-DUK_DOUBLE_INFINITY, -DUK_DOUBLE_INFINITY)));
  	DUK_ASSERT(duk_double_equals(DUK_FMOD(0.0, 1.0), 0.0) && DUK_SIGNBIT(DUK_FMOD(0.0, 1.0)) == 0);
  	DUK_ASSERT(duk_double_equals(DUK_FMOD(-0.0, 1.0), 0.0) && DUK_SIGNBIT(DUK_FMOD(-0.0, 1.0)) != 0);
  	DUK_ASSERT(duk_double_equals(DUK_FMOD(0.0, DUK_DOUBLE_INFINITY), 0.0) && DUK_SIGNBIT(DUK_FMOD(0.0, DUK_DOUBLE_INFINITY)) == 0);
  	DUK_ASSERT(duk_double_equals(DUK_FMOD(-0.0, DUK_DOUBLE_INFINITY), 0.0) && DUK_SIGNBIT(DUK_FMOD(-0.0, DUK_DOUBLE_INFINITY)) != 0);
  	DUK_ASSERT(duk_double_equals(DUK_FMOD(0.0, -DUK_DOUBLE_INFINITY), 0.0) && DUK_SIGNBIT(DUK_FMOD(0.0, DUK_DOUBLE_INFINITY)) == 0);
  	DUK_ASSERT(duk_double_equals(DUK_FMOD(-0.0, -DUK_DOUBLE_INFINITY), 0.0) && DUK_SIGNBIT(DUK_FMOD(-0.0, -DUK_DOUBLE_INFINITY)) != 0);
  	DUK_ASSERT(DUK_ISNAN(DUK_FMOD(0.0, 0.0)));
  	DUK_ASSERT(DUK_ISNAN(DUK_FMOD(-0.0, 0.0)));
  	DUK_ASSERT(DUK_ISNAN(DUK_FMOD(0.0, -0.0)));
  	DUK_ASSERT(DUK_ISNAN(DUK_FMOD(-0.0, -0.0)));
  	DUK_ASSERT(DUK_ISNAN(DUK_FMOD(0.0, DUK_DOUBLE_NAN)));
  	DUK_ASSERT(DUK_ISNAN(DUK_FMOD(-0.0, DUK_DOUBLE_NAN)));
  #endif
  
  	return (duk_double_t) DUK_FMOD((double) d1, (double) d2);
  }
  
  /* 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_double_equals(DUK_FABS(x), 1.0) && cy == DUK_FP_INFINITE) {
  		goto ret_nan;
  	}
  
  #if defined(DUK_USE_POW_WORKAROUNDS)
  	/* Specific fixes to common pow() implementation issues:
  	 *   - test-bug-netbsd-math-pow.js: NetBSD 6.0 on x86 (at least)
  	 *   - test-bug-mingw-math-issues.js
  	 */
  	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 if y<0 but not an odd integer
  			 * 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;
  			}
  		}
  	} else if (cx == DUK_FP_NAN) {
  		if (duk_double_equals(y, 0.0)) {
  			/* NaN ** +/- 0 should always be 1, but is NaN on
  			 * at least some Cygwin/MinGW versions.
  			 */
  			return 1.0;
  		}
  	}
  #else
  	/* Some ISO C assumptions. */
  	DUK_ASSERT(duk_double_equals(DUK_POW(DUK_DOUBLE_NAN, 0.0), 1.0));
  	DUK_ASSERT(DUK_ISINF(DUK_POW(0.0, -1.0)) && DUK_SIGNBIT(DUK_POW(0.0, -1.0)) == 0);
  	DUK_ASSERT(DUK_ISINF(DUK_POW(-0.0, -2.0)) && DUK_SIGNBIT(DUK_POW(-0.0, -2.0)) == 0);
  	DUK_ASSERT(DUK_ISINF(DUK_POW(-0.0, -3.0)) && DUK_SIGNBIT(DUK_POW(-0.0, -3.0)) != 0);
  #endif
  
  	return DUK_POW(x, y);
  
   ret_nan:
  	return DUK_DOUBLE_NAN;
  }
  