diff options
| -rw-r--r-- | etc/NEWS | 5 | ||||
| -rw-r--r-- | src/bytecode.c | 14 | ||||
| -rw-r--r-- | src/data.c | 86 | ||||
| -rw-r--r-- | test/src/data-tests.el | 6 |
4 files changed, 70 insertions, 41 deletions
| @@ -902,6 +902,11 @@ interpreting consecutive runs of numerical characters as numbers, and | |||
| 902 | compares their numerical values. According to this predicate, | 902 | compares their numerical values. According to this predicate, |
| 903 | "foo2.png" is smaller than "foo12.png". | 903 | "foo2.png" is smaller than "foo12.png". |
| 904 | 904 | ||
| 905 | --- | ||
| 906 | ** Numeric comparisons no longer return incorrect answers due to | ||
| 907 | internal rounding errors. For example, (< most-positive-fixnum (+ 1.0 | ||
| 908 | most-positive-fixnum)) now correctly returns t on 64-bit hosts. | ||
| 909 | |||
| 905 | +++ | 910 | +++ |
| 906 | ** The new function 'char-from-name' converts a Unicode name string | 911 | ** The new function 'char-from-name' converts a Unicode name string |
| 907 | to the corresponding character code. | 912 | to the corresponding character code. |
diff --git a/src/bytecode.c b/src/bytecode.c index 4414b077bb9..e781a87d16f 100644 --- a/src/bytecode.c +++ b/src/bytecode.c | |||
| @@ -992,18 +992,14 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, | |||
| 992 | CASE (Beqlsign): | 992 | CASE (Beqlsign): |
| 993 | { | 993 | { |
| 994 | Lisp_Object v2 = POP, v1 = TOP; | 994 | Lisp_Object v2 = POP, v1 = TOP; |
| 995 | CHECK_NUMBER_OR_FLOAT_COERCE_MARKER (v1); | ||
| 996 | CHECK_NUMBER_OR_FLOAT_COERCE_MARKER (v2); | ||
| 997 | bool equal; | ||
| 998 | if (FLOATP (v1) || FLOATP (v2)) | 995 | if (FLOATP (v1) || FLOATP (v2)) |
| 996 | TOP = arithcompare (v1, v2, ARITH_EQUAL); | ||
| 997 | else | ||
| 999 | { | 998 | { |
| 1000 | double f1 = FLOATP (v1) ? XFLOAT_DATA (v1) : XINT (v1); | 999 | CHECK_NUMBER_OR_FLOAT_COERCE_MARKER (v1); |
| 1001 | double f2 = FLOATP (v2) ? XFLOAT_DATA (v2) : XINT (v2); | 1000 | CHECK_NUMBER_OR_FLOAT_COERCE_MARKER (v2); |
| 1002 | equal = f1 == f2; | 1001 | TOP = EQ (v1, v2) ? Qt : Qnil; |
| 1003 | } | 1002 | } |
| 1004 | else | ||
| 1005 | equal = XINT (v1) == XINT (v2); | ||
| 1006 | TOP = equal ? Qt : Qnil; | ||
| 1007 | NEXT; | 1003 | NEXT; |
| 1008 | } | 1004 | } |
| 1009 | 1005 | ||
diff --git a/src/data.c b/src/data.c index 32ec89871a8..88d86697e42 100644 --- a/src/data.c +++ b/src/data.c | |||
| @@ -2392,68 +2392,90 @@ bool-vector. IDX starts at 0. */) | |||
| 2392 | /* Arithmetic functions */ | 2392 | /* Arithmetic functions */ |
| 2393 | 2393 | ||
| 2394 | Lisp_Object | 2394 | Lisp_Object |
| 2395 | arithcompare (Lisp_Object num1, Lisp_Object num2, enum Arith_Comparison comparison) | 2395 | arithcompare (Lisp_Object num1, Lisp_Object num2, |
| 2396 | enum Arith_Comparison comparison) | ||
| 2396 | { | 2397 | { |
| 2397 | double f1 = 0, f2 = 0; | 2398 | double f1, f2; |
| 2398 | bool floatp = 0; | 2399 | EMACS_INT i1, i2; |
| 2400 | bool fneq; | ||
| 2401 | bool test; | ||
| 2399 | 2402 | ||
| 2400 | CHECK_NUMBER_OR_FLOAT_COERCE_MARKER (num1); | 2403 | CHECK_NUMBER_OR_FLOAT_COERCE_MARKER (num1); |
| 2401 | CHECK_NUMBER_OR_FLOAT_COERCE_MARKER (num2); | 2404 | CHECK_NUMBER_OR_FLOAT_COERCE_MARKER (num2); |
| 2402 | 2405 | ||
| 2403 | if (FLOATP (num1) || FLOATP (num2)) | 2406 | /* If either arg is floating point, set F1 and F2 to the 'double' |
| 2407 | approximations of the two arguments. Regardless, set I1 and I2 | ||
| 2408 | to integers that break ties if the floating point comparison is | ||
| 2409 | either not done or reports equality. */ | ||
| 2410 | |||
| 2411 | if (FLOATP (num1)) | ||
| 2412 | { | ||
| 2413 | f1 = XFLOAT_DATA (num1); | ||
| 2414 | if (FLOATP (num2)) | ||
| 2415 | { | ||
| 2416 | i1 = i2 = 0; | ||
| 2417 | f2 = XFLOAT_DATA (num2); | ||
| 2418 | } | ||
| 2419 | else | ||
| 2420 | i1 = f2 = i2 = XINT (num2); | ||
| 2421 | fneq = f1 != f2; | ||
| 2422 | } | ||
| 2423 | else | ||
| 2404 | { | 2424 | { |
| 2405 | floatp = 1; | 2425 | i1 = XINT (num1); |
| 2406 | f1 = (FLOATP (num1)) ? XFLOAT_DATA (num1) : XINT (num1); | 2426 | if (FLOATP (num2)) |
| 2407 | f2 = (FLOATP (num2)) ? XFLOAT_DATA (num2) : XINT (num2); | 2427 | { |
| 2428 | i2 = f1 = i1; | ||
| 2429 | f2 = XFLOAT_DATA (num2); | ||
| 2430 | fneq = f1 != f2; | ||
| 2431 | } | ||
| 2432 | else | ||
| 2433 | { | ||
| 2434 | i2 = XINT (num2); | ||
| 2435 | fneq = false; | ||
| 2436 | } | ||
| 2408 | } | 2437 | } |
| 2409 | 2438 | ||
| 2410 | switch (comparison) | 2439 | switch (comparison) |
| 2411 | { | 2440 | { |
| 2412 | case ARITH_EQUAL: | 2441 | case ARITH_EQUAL: |
| 2413 | if (floatp ? f1 == f2 : XINT (num1) == XINT (num2)) | 2442 | test = !fneq && i1 == i2; |
| 2414 | return Qt; | 2443 | break; |
| 2415 | return Qnil; | ||
| 2416 | 2444 | ||
| 2417 | case ARITH_NOTEQUAL: | 2445 | case ARITH_NOTEQUAL: |
| 2418 | if (floatp ? f1 != f2 : XINT (num1) != XINT (num2)) | 2446 | test = fneq || i1 != i2; |
| 2419 | return Qt; | 2447 | break; |
| 2420 | return Qnil; | ||
| 2421 | 2448 | ||
| 2422 | case ARITH_LESS: | 2449 | case ARITH_LESS: |
| 2423 | if (floatp ? f1 < f2 : XINT (num1) < XINT (num2)) | 2450 | test = fneq ? f1 < f2 : i1 < i2; |
| 2424 | return Qt; | 2451 | break; |
| 2425 | return Qnil; | ||
| 2426 | 2452 | ||
| 2427 | case ARITH_LESS_OR_EQUAL: | 2453 | case ARITH_LESS_OR_EQUAL: |
| 2428 | if (floatp ? f1 <= f2 : XINT (num1) <= XINT (num2)) | 2454 | test = fneq ? f1 <= f2 : i1 <= i2; |
| 2429 | return Qt; | 2455 | break; |
| 2430 | return Qnil; | ||
| 2431 | 2456 | ||
| 2432 | case ARITH_GRTR: | 2457 | case ARITH_GRTR: |
| 2433 | if (floatp ? f1 > f2 : XINT (num1) > XINT (num2)) | 2458 | test = fneq ? f1 > f2 : i1 > i2; |
| 2434 | return Qt; | 2459 | break; |
| 2435 | return Qnil; | ||
| 2436 | 2460 | ||
| 2437 | case ARITH_GRTR_OR_EQUAL: | 2461 | case ARITH_GRTR_OR_EQUAL: |
| 2438 | if (floatp ? f1 >= f2 : XINT (num1) >= XINT (num2)) | 2462 | test = fneq ? f1 >= f2 : i1 >= i2; |
| 2439 | return Qt; | 2463 | break; |
| 2440 | return Qnil; | ||
| 2441 | 2464 | ||
| 2442 | default: | 2465 | default: |
| 2443 | emacs_abort (); | 2466 | eassume (false); |
| 2444 | } | 2467 | } |
| 2468 | |||
| 2469 | return test ? Qt : Qnil; | ||
| 2445 | } | 2470 | } |
| 2446 | 2471 | ||
| 2447 | static Lisp_Object | 2472 | static Lisp_Object |
| 2448 | arithcompare_driver (ptrdiff_t nargs, Lisp_Object *args, | 2473 | arithcompare_driver (ptrdiff_t nargs, Lisp_Object *args, |
| 2449 | enum Arith_Comparison comparison) | 2474 | enum Arith_Comparison comparison) |
| 2450 | { | 2475 | { |
| 2451 | ptrdiff_t argnum; | 2476 | for (ptrdiff_t i = 1; i < nargs; i++) |
| 2452 | for (argnum = 1; argnum < nargs; ++argnum) | 2477 | if (NILP (arithcompare (args[i - 1], args[i], comparison))) |
| 2453 | { | 2478 | return Qnil; |
| 2454 | if (EQ (Qnil, arithcompare (args[argnum - 1], args[argnum], comparison))) | ||
| 2455 | return Qnil; | ||
| 2456 | } | ||
| 2457 | return Qt; | 2479 | return Qt; |
| 2458 | } | 2480 | } |
| 2459 | 2481 | ||
diff --git a/test/src/data-tests.el b/test/src/data-tests.el index 2e4a6aa2e8a..d38760cdde6 100644 --- a/test/src/data-tests.el +++ b/test/src/data-tests.el | |||
| @@ -29,6 +29,8 @@ | |||
| 29 | (should (= 1)) | 29 | (should (= 1)) |
| 30 | (should (= 2 2)) | 30 | (should (= 2 2)) |
| 31 | (should (= 9 9 9 9 9 9 9 9 9)) | 31 | (should (= 9 9 9 9 9 9 9 9 9)) |
| 32 | (should (= most-negative-fixnum (float most-negative-fixnum))) | ||
| 33 | (should-not (= most-positive-fixnum (+ 1.0 most-positive-fixnum))) | ||
| 32 | (should-not (apply #'= '(3 8 3))) | 34 | (should-not (apply #'= '(3 8 3))) |
| 33 | (should-error (= 9 9 'foo)) | 35 | (should-error (= 9 9 'foo)) |
| 34 | ;; Short circuits before getting to bad arg | 36 | ;; Short circuits before getting to bad arg |
| @@ -39,6 +41,7 @@ | |||
| 39 | (should (< 1)) | 41 | (should (< 1)) |
| 40 | (should (< 2 3)) | 42 | (should (< 2 3)) |
| 41 | (should (< -6 -1 0 2 3 4 8 9 999)) | 43 | (should (< -6 -1 0 2 3 4 8 9 999)) |
| 44 | (should (< 0.5 most-positive-fixnum (+ 1.0 most-positive-fixnum))) | ||
| 42 | (should-not (apply #'< '(3 8 3))) | 45 | (should-not (apply #'< '(3 8 3))) |
| 43 | (should-error (< 9 10 'foo)) | 46 | (should-error (< 9 10 'foo)) |
| 44 | ;; Short circuits before getting to bad arg | 47 | ;; Short circuits before getting to bad arg |
| @@ -49,6 +52,7 @@ | |||
| 49 | (should (> 1)) | 52 | (should (> 1)) |
| 50 | (should (> 3 2)) | 53 | (should (> 3 2)) |
| 51 | (should (> 6 1 0 -2 -3 -4 -8 -9 -999)) | 54 | (should (> 6 1 0 -2 -3 -4 -8 -9 -999)) |
| 55 | (should (> (+ 1.0 most-positive-fixnum) most-positive-fixnum 0.5)) | ||
| 52 | (should-not (apply #'> '(3 8 3))) | 56 | (should-not (apply #'> '(3 8 3))) |
| 53 | (should-error (> 9 8 'foo)) | 57 | (should-error (> 9 8 'foo)) |
| 54 | ;; Short circuits before getting to bad arg | 58 | ;; Short circuits before getting to bad arg |
| @@ -59,6 +63,7 @@ | |||
| 59 | (should (<= 1)) | 63 | (should (<= 1)) |
| 60 | (should (<= 2 3)) | 64 | (should (<= 2 3)) |
| 61 | (should (<= -6 -1 -1 0 0 0 2 3 4 8 999)) | 65 | (should (<= -6 -1 -1 0 0 0 2 3 4 8 999)) |
| 66 | (should (<= 0.5 most-positive-fixnum (+ 1.0 most-positive-fixnum))) | ||
| 62 | (should-not (apply #'<= '(3 8 3 3))) | 67 | (should-not (apply #'<= '(3 8 3 3))) |
| 63 | (should-error (<= 9 10 'foo)) | 68 | (should-error (<= 9 10 'foo)) |
| 64 | ;; Short circuits before getting to bad arg | 69 | ;; Short circuits before getting to bad arg |
| @@ -69,6 +74,7 @@ | |||
| 69 | (should (>= 1)) | 74 | (should (>= 1)) |
| 70 | (should (>= 3 2)) | 75 | (should (>= 3 2)) |
| 71 | (should (>= 666 1 0 0 -2 -3 -3 -3 -4 -8 -8 -9 -999)) | 76 | (should (>= 666 1 0 0 -2 -3 -3 -3 -4 -8 -8 -9 -999)) |
| 77 | (should (>= (+ 1.0 most-positive-fixnum) most-positive-fixnum)) | ||
| 72 | (should-not (apply #'>= '(3 8 3))) | 78 | (should-not (apply #'>= '(3 8 3))) |
| 73 | (should-error (>= 9 8 'foo)) | 79 | (should-error (>= 9 8 'foo)) |
| 74 | ;; Short circuits before getting to bad arg | 80 | ;; Short circuits before getting to bad arg |