From: Artem S. Povalyukhin Date: Thu, 31 Oct 2019 19:18:41 +0000 (+0300) Subject: Fixed handling of NaN and -0 arguments in Math.min(), Math.max(). X-Git-Tag: 0.3.7~9 X-Git-Url: http://www.kaiwu.me/postgresql/commit/?a=commitdiff_plain;h=b647843b85309319ffae3656e3151f8cbc8889bc;p=njs.git Fixed handling of NaN and -0 arguments in Math.min(), Math.max(). This closes #241 issue on Github. --- diff --git a/src/njs_math.c b/src/njs_math.c index d1821f99..42201ff7 100644 --- a/src/njs_math.c +++ b/src/njs_math.c @@ -628,75 +628,53 @@ njs_object_math_log2(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, } -static njs_int_t -njs_object_math_max(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, - njs_index_t unused) +njs_inline double +njs_fmax(double x, double y) { - double num; - njs_int_t ret; - njs_uint_t i; - - if (nargs > 1) { - for (i = 1; i < nargs; i++) { - if (njs_is_undefined(&args[i])) { - num = NAN; - goto done; - - } else if (!njs_is_numeric(&args[i])) { - ret = njs_value_to_numeric(vm, &args[i], &args[i]); - if (ret != NJS_OK) { - return ret; - } - } - } + if (x == 0 && y == 0) { + return signbit(x) ? y : x; + } - num = njs_number(&args[1]); + return fmax(x, y); +} - for (i = 2; i < nargs; i++) { - num = fmax(num, njs_number(&args[i])); - } - } else { - num = -INFINITY; +njs_inline double +njs_fmin(double x, double y) +{ + if (x == 0 && y == 0) { + return signbit(x) ? x : y; } -done: - - njs_set_number(&vm->retval, num); - - return NJS_OK; + return fmin(x, y); } static njs_int_t -njs_object_math_min(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, - njs_index_t unused) +njs_object_math_min_max(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, + njs_index_t max) { - double num; + double num, value; njs_int_t ret; njs_uint_t i; - if (nargs > 1) { - for (i = 1; i < nargs; i++) { - if (!njs_is_numeric(&args[i])) { - ret = njs_value_to_numeric(vm, &args[i], &args[i]); - if (ret != NJS_OK) { - return ret; - } - } - } + value = max ? -INFINITY : INFINITY; - num = njs_number(&args[1]); + for (i = 1; i < nargs; i++) { + ret = njs_value_to_number(vm, &args[i], &num); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } - for (i = 2; i < nargs; i++) { - num = fmin(num, njs_number(&args[i])); + if (njs_slow_path(isnan(num))) { + value = num; + break; } - } else { - num = INFINITY; + value = max ? njs_fmax(value, num) : njs_fmin(value, num); } - njs_set_number(&vm->retval, num); + njs_set_number(&vm->retval, value); return NJS_OK; } @@ -1221,7 +1199,7 @@ static const njs_object_prop_t njs_math_object_properties[] = { .type = NJS_PROPERTY, .name = njs_string("max"), - .value = njs_native_function(njs_object_math_max, 2), + .value = njs_native_function2(njs_object_math_min_max, 2, 1), .writable = 1, .configurable = 1, }, @@ -1229,7 +1207,7 @@ static const njs_object_prop_t njs_math_object_properties[] = { .type = NJS_PROPERTY, .name = njs_string("min"), - .value = njs_native_function(njs_object_math_min, 2), + .value = njs_native_function2(njs_object_math_min_max, 2, 0), .writable = 1, .configurable = 1, }, diff --git a/src/test/njs_unit_test.c b/src/test/njs_unit_test.c index 40c86a36..4412f658 100644 --- a/src/test/njs_unit_test.c +++ b/src/test/njs_unit_test.c @@ -12828,12 +12828,24 @@ static njs_unit_test_t njs_test[] = { njs_str("Math.max()"), njs_str("-Infinity") }, + { njs_str("Math.max(0, -0)"), + njs_str("0") }, + + { njs_str("Math.max(-0, 0)"), + njs_str("0") }, + { njs_str("Math.max(null)"), njs_str("0") }, { njs_str("Math.max(undefined)"), njs_str("NaN") }, + { njs_str("Math.max(1, 2, 3, undefined)"), + njs_str("NaN") }, + + { njs_str("Math.max(1, 2, 3, NaN)"), + njs_str("NaN") }, + { njs_str("Math.max('1', '2', '5')"), njs_str("5") }, @@ -12852,12 +12864,24 @@ static njs_unit_test_t njs_test[] = { njs_str("Math.min()"), njs_str("Infinity") }, + { njs_str("Math.min(0, -0)"), + njs_str("-0") }, + + { njs_str("Math.min(-0, 0)"), + njs_str("-0") }, + { njs_str("Math.min(null)"), njs_str("0") }, { njs_str("Math.min(undefined)"), njs_str("NaN") }, + { njs_str("Math.min(1, 2, 3, undefined)"), + njs_str("NaN") }, + + { njs_str("Math.min(1, 2, 3, NaN)"), + njs_str("NaN") }, + { njs_str("Math.min('1', '2', '5')"), njs_str("1") },