From 9b69ea4d6d7cc785f30d316ab81dd5aa8e32b560 Mon Sep 17 00:00:00 2001 From: Ruben Ayrapetyan Date: Tue, 23 Sep 2014 21:56:44 +0400 Subject: [PATCH] Implementing Math.sqrt. --- .../ecma-builtin-math-object.c | 67 ++++++++++++++++++- src/libecmaobjects/ecma-globals.h | 5 ++ tests/jerry/sqrt.js | 31 +++++++++ 3 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 tests/jerry/sqrt.js diff --git a/src/libecmabuiltins/ecma-builtin-math-object.c b/src/libecmabuiltins/ecma-builtin-math-object.c index afcdb8a76..71bde890b 100644 --- a/src/libecmabuiltins/ecma-builtin-math-object.c +++ b/src/libecmabuiltins/ecma-builtin-math-object.c @@ -39,6 +39,14 @@ * @{ */ +#if defined (CONFIG_ECMA_NUMBER_FLOAT32) +const ecma_number_t ecma_builtin_math_object_relative_eps = 1.0e-10f; +#elif defined (CONFIG_ECMA_NUMBER_FLOAT64) +const ecma_number_t ecma_builtin_math_object_relative_eps = 1.0e-16f; +#else /* !CONFIG_ECMA_NUMBER_FLOAT32 && !CONFIG_ECMA_NUMBER_FLOAT64 */ +# error "!CONFIG_ECMA_NUMBER_FLOAT32 && !CONFIG_ECMA_NUMBER_FLOAT64" +#endif /* !CONFIG_ECMA_NUMBER_FLOAT32 && !CONFIG_ECMA_NUMBER_FLOAT64 */ + /** * List of the Math object built-in value properties in format 'macro (name, value)'. */ @@ -646,7 +654,64 @@ ecma_builtin_math_object_sin (ecma_value_t arg) /**< routine's argument */ static ecma_completion_value_t ecma_builtin_math_object_sqrt (ecma_value_t arg) /**< routine's argument */ { - JERRY_UNIMPLEMENTED_REF_UNUSED_VARS (arg); + ecma_completion_value_t ret_value; + + ECMA_TRY_CATCH (arg_num_value, + ecma_op_to_number (arg), + ret_value); + + const ecma_number_t arg_num = *(ecma_number_t*) ECMA_GET_POINTER (arg_num_value.u.value.value); + ecma_number_t ret_num; + + if (ecma_number_is_nan (arg_num) + || (!ecma_number_is_zero (arg_num) + && ecma_number_is_negative (arg_num))) + { + ret_num = ecma_number_make_nan (); + } + else if (ecma_number_is_zero (arg_num)) + { + ret_num = arg_num; + } + else if (ecma_number_is_infinity (arg_num)) + { + JERRY_ASSERT (!ecma_number_is_negative (arg_num)); + + ret_num = arg_num; + } + else + { + /* Newton's method */ + + ecma_number_t x = ECMA_NUMBER_ONE; + ecma_number_t diff = ecma_number_make_infinity (false); + + while (ecma_op_number_divide (diff, x) > ecma_builtin_math_object_relative_eps) + { + ecma_number_t x_next = ecma_op_number_multiply (ECMA_NUMBER_HALF, + (ecma_op_number_add (x, + ecma_op_number_divide (arg_num, x)))); + + diff = ecma_op_number_substract (x, x_next); + if (diff < 0) + { + diff = ecma_number_negate (diff); + } + + x = x_next; + } + + ret_num = x; + } + + ecma_number_t *num_p = ecma_alloc_number (); + *num_p = ret_num; + + ret_value = ecma_make_return_completion_value (ecma_make_number_value (num_p)); + + ECMA_FINALIZE (arg_num_value); + + return ret_value; } /* ecma_builtin_math_object_sqrt */ /** diff --git a/src/libecmaobjects/ecma-globals.h b/src/libecmaobjects/ecma-globals.h index 3bb5991a9..64d5f3b0f 100644 --- a/src/libecmaobjects/ecma-globals.h +++ b/src/libecmaobjects/ecma-globals.h @@ -560,6 +560,11 @@ typedef double ecma_number_t; */ #define ECMA_NUMBER_ONE ((ecma_number_t) 1) +/** + * Value '0.5' of ecma_number_t + */ +#define ECMA_NUMBER_HALF ((ecma_number_t) 0.5f) + /** * Null character (zt-string end marker) */ diff --git a/tests/jerry/sqrt.js b/tests/jerry/sqrt.js new file mode 100644 index 000000000..9240fd420 --- /dev/null +++ b/tests/jerry/sqrt.js @@ -0,0 +1,31 @@ +// Copyright 2014 Samsung Electronics Co., Ltd. +// +// 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. + +assert(isNaN(Math['sqrt'] (NaN))); +assert(isNaN(Math['sqrt'] (-1.0))); +assert(isNaN(Math['sqrt'] (-Infinity))); +assert(Math['sqrt'] (0.0) === 0.0); +assert(Math['sqrt'] (Infinity) === Infinity); + +assert(Math['sqrt'] (1.0) === 1.0); +assert(Math['sqrt'] (2.0) === Math['SQRT2']); +assert(Math['sqrt'] (0.5) === Math['SQRT1_2']); + +var sqrt_1e38 = Math['sqrt'] (1.0e+38); +assert(sqrt_1e38 > 0.999999 * 1.0e+19); +assert(sqrt_1e38 < 1.000001 * 1.0e+19); + +var sqrt_1e38 = Math['sqrt'] (1.0e-38); +assert(sqrt_1e38 > 0.999999 * 1.0e-19); +assert(sqrt_1e38 < 1.000001 * 1.0e-19);