diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-math.c b/jerry-core/ecma/builtin-objects/ecma-builtin-math.c index f7e8a8a14..f7bf2abec 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-math.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-math.c @@ -552,11 +552,7 @@ ecma_builtin_math_dispatch_routine (uint16_t builtin_routine_id, /**< built-in w } case ECMA_MATH_OBJECT_CBRT: { -#ifdef JERRY_LIBM_MATH_H - return ecma_raise_type_error (ECMA_ERR_MSG ("UNIMPLEMENTED: Math.cbrt")); -#else /* !JERRY_LIBM_MATH_H */ x = DOUBLE_TO_ECMA_NUMBER_T (cbrt (x)); -#endif /* JERRY_LIBM_MATH_H */ break; } case ECMA_MATH_OBJECT_COSH: diff --git a/jerry-libm/cbrt.c b/jerry-libm/cbrt.c new file mode 100644 index 000000000..cedb2a9d8 --- /dev/null +++ b/jerry-libm/cbrt.c @@ -0,0 +1,103 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is based on work under the following copyright and permission + * notice: + * + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * + * @(#)s_cbrt.c 1.3 95/01/18 + */ + +#include "jerry-libm-internal.h" + +/* cbrt(x) + * Return cube root of x + */ + +#define B1 715094163 /* B1 = (682 - 0.03306235651) * 2**20 */ +#define B2 696219795 /* B2 = (664 - 0.03306235651) * 2**20 */ +#define C 5.42857142857142815906e-01 /* 19/35 = 0x3FE15F15, 0xF15F15F1 */ +#define D -7.05306122448979611050e-01 /* -864/1225 = 0xBFE691DE, 0x2532C834 */ +#define E 1.41428571428571436819e+00 /* 99/70 = 0x3FF6A0EA, 0x0EA0EA0F */ +#define F 1.60714285714285720630e+00 /* 45/28 = 0x3FF9B6DB, 0x6DB6DB6E */ +#define G 3.57142857142857150787e-01 /* 5/14 = 0x3FD6DB6D, 0xB6DB6DB7 */ + +double +cbrt (double x) +{ + double r, s, w; + double_accessor t, temp; + unsigned int sign; + t.dbl = 0.0; + temp.dbl = x; + + sign = temp.as_int.hi & 0x80000000; /* sign = sign(x) */ + temp.as_int.hi ^= sign; + + if (temp.as_int.hi >= 0x7ff00000) + { + /* cbrt(NaN, INF) is itself */ + return (x + x); + } + if ((temp.as_int.hi | temp.as_int.lo) == 0) + { + /* cbrt(0) is itself */ + return (x); + } + /* rough cbrt to 5 bits */ + if (temp.as_int.hi < 0x00100000) /* subnormal number */ + { + t.as_int.hi = 0x43500000; /* set t= 2**54 */ + t.dbl *= temp.dbl; + t.as_int.hi = t.as_int.hi / 3 + B2; + } + else + { + t.as_int.hi = temp.as_int.hi / 3 + B1; + } + + /* new cbrt to 23 bits, may be implemented in single precision */ + r = t.dbl * t.dbl / temp.dbl; + s = C + r * t.dbl; + t.dbl *= G + F / (s + E + D / s); + + /* chopped to 20 bits and make it larger than cbrt(x) */ + t.as_int.lo = 0; + t.as_int.hi += 0x00000001; + + /* one step newton iteration to 53 bits with error less than 0.667 ulps */ + s = t.dbl * t.dbl; /* t*t is exact */ + r = temp.dbl / s; + w = t.dbl + t.dbl; + r = (r - t.dbl) / (w + r); /* r-s is exact */ + t.dbl = t.dbl + (t.dbl * r); + + /* retore the sign bit */ + t.as_int.hi |= sign; + return (t.dbl); +} /* cbrt */ + +#undef B1 +#undef B2 +#undef C +#undef D +#undef E +#undef F +#undef G diff --git a/jerry-libm/include/math.h b/jerry-libm/include/math.h index 734f883ba..d3b391699 100644 --- a/jerry-libm/include/math.h +++ b/jerry-libm/include/math.h @@ -67,6 +67,7 @@ double log10 (double); /* Power functions. */ double pow (double, double); double sqrt (double); +double cbrt (double); /* Rounding and remainder functions. */ double ceil (double); diff --git a/jerry-libm/jerry-libm-internal.h b/jerry-libm/jerry-libm-internal.h index b766cda53..7ed7579bf 100644 --- a/jerry-libm/jerry-libm-internal.h +++ b/jerry-libm/jerry-libm-internal.h @@ -97,6 +97,7 @@ double log10 (double); double pow (double x, double y); double sqrt (double x); +double cbrt (double); double ceil (double x); double fabs (double x); diff --git a/tests/jerry/es2015/math-cbrt.js b/tests/jerry/es2015/math-cbrt.js new file mode 100644 index 000000000..700408a25 --- /dev/null +++ b/tests/jerry/es2015/math-cbrt.js @@ -0,0 +1,33 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var p_zero = 0.0; +var n_zero = -p_zero; + +function isSameZero (x, y) +{ + return x === 0 && (1 / x) === (1 / y); +} + +assert(isNaN(Math.cbrt(NaN))); +assert(isSameZero(Math.cbrt(p_zero), p_zero)); +assert(isSameZero(Math.cbrt(n_zero), n_zero)); +assert(Math.cbrt(Number.POSITIVE_INFINITY) === Number.POSITIVE_INFINITY); +assert(Math.cbrt(Number.NEGATIVE_INFINITY) === Number.NEGATIVE_INFINITY); + +assert(Math.cbrt(1.0) === 1.0); +assert(Math.cbrt(-1.0) === -1.0); + +assert(Math.cbrt(27.0) === 3.0); +assert(Math.cbrt(0.001) === 0.1); diff --git a/tests/unit-libm/test-libm.inc.h b/tests/unit-libm/test-libm.inc.h index 8cfdd0d84..edbcf0cc7 100644 --- a/tests/unit-libm/test-libm.inc.h +++ b/tests/unit-libm/test-libm.inc.h @@ -531,6 +531,29 @@ check_double ("sqrt (4)", sqrt (4), 2.00000000000000000000E+00); check_double ("sqrt (0.25)", sqrt (0.25), 5.00000000000000000000E-01); check_double ("sqrt (6642.25)", sqrt (6642.25), 8.15000000000000000000E+01); check_double ("sqrt (15239.9025)", sqrt (15239.9025), 1.23450000000000002842E+02); +check_double ("cbrt (0.0)", cbrt (0.0), 0.00000000000000000000E+00); +check_double ("cbrt (-0.0)", cbrt (-0.0), -0.00000000000000000000E+00); +check_double ("cbrt (1.0)", cbrt (1.0), 1.00000000000000000000E+00); +check_double ("cbrt (-1.0)", cbrt (-1.0), -1.00000000000000000000E+00); +check_double ("cbrt (INFINITY)", cbrt (INFINITY), INF); +check_double ("cbrt (-INFINITY)", cbrt (-INFINITY), -INF); +check_double ("cbrt (NAN)", cbrt (NAN), NAN); +check_double ("cbrt (0.7)", cbrt (0.7), 8.87904001742600645919E-01); +check_double ("cbrt (2)", cbrt (2), 1.25992104989487319067E+00); +check_double ("cbrt (10)", cbrt (10), 2.15443469003188381450E+00); +check_double ("cbrt (2.22e-308)", cbrt (2.22e-308), 2.81050475771047639693E-103); +check_double ("cbrt (2.23e-308)", cbrt (2.23e-308), 2.81471841433133404618E-103); +check_double ("cbrt (3.72e-09)", cbrt (3.72e-09), 1.54946217899915657419E-03); +check_double ("cbrt (7.37e+19)", cbrt (7.37e+19), 4.19265534205965511501E+06); +check_double ("cbrt (2209)", cbrt (2209), 1.30236256766892157799E+01); +check_double ("cbrt (4)", cbrt (4), 1.58740105196819958344E+00); +check_double ("cbrt (0.25)", cbrt (0.25), 6.29960524947436595333E-01); +check_double ("cbrt (6642.25)", cbrt (6642.25), 1.87977155063238647870E+01); +check_double ("cbrt (15239.9025)", cbrt (15239.9025), 2.47929038511971775449E+01); +check_double ("cbrt (3)", cbrt (3), 1.44224957030740830177E+00); +check_double ("cbrt (9)", cbrt (9), 2.08008382305190409056E+00); +check_double ("cbrt (-17.87)", cbrt (-17.87), -2.61441695192974155049E+00); +check_double ("cbrt (-8941)", cbrt (-8941), -2.07552848589356599973E+01); check_double ("sin (0.0)", sin (0.0), 0.00000000000000000000E+00); check_double ("sin (-0.0)", sin (-0.0), -0.00000000000000000000E+00); check_double ("sin (1.0)", sin (1.0), 8.41470984807896504876E-01); diff --git a/tools/unit-tests/gen-test-libm.c b/tools/unit-tests/gen-test-libm.c index 21e55928a..ee2ffaae5 100644 --- a/tools/unit-tests/gen-test-libm.c +++ b/tools/unit-tests/gen-test-libm.c @@ -717,6 +717,31 @@ main (int argc, char **args) GEN_DBL_TEST (sqrt (6642.25)); GEN_DBL_TEST (sqrt (15239.9025)); + /* cbrt tests */ + GEN_DBL_TEST (cbrt (0.0)); + GEN_DBL_TEST (cbrt (-0.0)); + GEN_DBL_TEST (cbrt (1.0)); + GEN_DBL_TEST (cbrt (-1.0)); + GEN_DBL_TEST (cbrt (INFINITY)); + GEN_DBL_TEST (cbrt (-INFINITY)); + GEN_DBL_TEST (cbrt (NAN)); + GEN_DBL_TEST (cbrt (0.7)); + GEN_DBL_TEST (cbrt (2)); + GEN_DBL_TEST (cbrt (10)); + GEN_DBL_TEST (cbrt (2.22e-308)); + GEN_DBL_TEST (cbrt (2.23e-308)); + GEN_DBL_TEST (cbrt (3.72e-09)); + GEN_DBL_TEST (cbrt (7.37e+19)); + GEN_DBL_TEST (cbrt (2209)); + GEN_DBL_TEST (cbrt (4)); + GEN_DBL_TEST (cbrt (0.25)); + GEN_DBL_TEST (cbrt (6642.25)); + GEN_DBL_TEST (cbrt (15239.9025)); + GEN_DBL_TEST (cbrt (3)); + GEN_DBL_TEST (cbrt (9)); + GEN_DBL_TEST (cbrt (-17.87)); + GEN_DBL_TEST (cbrt (-8941)); + /* sin tests */ GEN_DBL_TEST (sin (0.0)); GEN_DBL_TEST (sin (-0.0));