diff --git a/src/duk_builtin_math.c b/src/duk_builtin_math.c index d3abea2c..7d62d595 100644 --- a/src/duk_builtin_math.c +++ b/src/duk_builtin_math.c @@ -67,7 +67,11 @@ static double fmin_fixed(double x, double y) { return +0.0; } } +#ifdef DUK_USE_MATH_FMIN return fmin(x, y); +#else + return (x < y ? x : y); +#endif } static double fmax_fixed(double x, double y) { @@ -81,16 +85,20 @@ static double fmax_fixed(double x, double y) { return -0.0; } } +#ifdef DUK_USE_MATH_FMAX return fmax(x, y); +#else + return (x > y ? x : y); +#endif } static double round_fixed(double x) { - /* Numbers must be rounded towards +Infinity, e.g. -3.5 must - * be rounded to -3 (not -4). When rounded to zero, zero sign - * must be set appropriately. E5.1 Section 15.8.2.15. + /* Numbers half-way between integers must be rounded towards +Infinity, + * e.g. -3.5 must be rounded to -3 (not -4). When rounded to zero, zero + * sign must be set appropriately. E5.1 Section 15.8.2.15. * - * Note that ANSI C round() is "round to nearest integer, away - * from zero", which is incorrect for negative values. + * Note that ANSI C round() is "round to nearest integer, away from zero", + * which is incorrect for negative values. Here we make do with floor(). */ int c = fpclassify(x); @@ -98,22 +106,31 @@ static double round_fixed(double x) { return x; } - if (x >= 0.0) { - /* FIXME: rely on [0,0.5[ rounding to +0? */ - if (x < 0.5) { - return +0.0; - } else { - return round(x); - } - } else { - if (x >= -0.5) { + /* + * x is finite and non-zero + * + * -1.6 -> floor(-1.1) -> -2 + * -1.5 -> floor(-1.0) -> -1 (towards +Inf) + * -1.4 -> floor(-0.9) -> -1 + * -0.5 -> -0.0 (special case) + * -0.1 -> -0.0 (special case) + * +0.1 -> +0.0 (special case) + * +0.5 -> floor(+1.0) -> 1 (towards +Inf) + * +1.4 -> floor(+1.9) -> 1 + * +1.5 -> floor(+2.0) -> 2 (towards +Inf) + * +1.6 -> floor(+2.1) -> 2 + */ + + if (x >= -0.5 && x < 0.5) { + /* +0.5 is handled by floor, this is on purpose */ + if (x < 0.0) { return -0.0; } else { - x = floor(x + 0.5); - DUK_ASSERT(x <= -1.0); - return x; + return +0.0; } } + + return floor(x + 0.5); } static double pow_fixed(double x, double y) {