]> git.kaiwu.me - njs.git/commitdiff
Fixed handling of NaN and -0 arguments in Math.min(), Math.max().
authorArtem S. Povalyukhin <artem.povaluhin@gmail.com>
Thu, 31 Oct 2019 19:18:41 +0000 (22:18 +0300)
committerArtem S. Povalyukhin <artem.povaluhin@gmail.com>
Thu, 31 Oct 2019 19:18:41 +0000 (22:18 +0300)
This closes #241 issue on Github.

src/njs_math.c
src/test/njs_unit_test.c

index d1821f9902c0c4b8e4d86f36f61d61e42acb6ebf..42201ff747576247a4d084a21f402bb5087f641e 100644 (file)
@@ -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,
     },
index 40c86a36a066648cbe280fa3292c99853099512e..4412f658dce5de0f10ee4ed23ca4c0016af02b32 100644 (file)
@@ -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") },