aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Eggert2017-03-02 09:11:11 -0800
committerPaul Eggert2017-03-02 09:12:49 -0800
commit4e2622bf0d63c40f447d44e6401ea054ef55b261 (patch)
tree10f66df3cd59695ffe15546aaa961987a3fe2ba1
parentd546be31a9320d94769cb322f008f49d08d852a8 (diff)
downloademacs-4e2622bf0d63c40f447d44e6401ea054ef55b261.tar.gz
emacs-4e2622bf0d63c40f447d44e6401ea054ef55b261.zip
Fix rounding errors in <, =, etc.
* etc/NEWS: Document this. * src/bytecode.c (exec_byte_code): * src/data.c (arithcompare): Do not lose information when comparing floats to integers. * test/src/data-tests.el (data-tests-=, data-tests-<) (data-tests->, data-tests-<=, data-tests->=): Test this.
-rw-r--r--etc/NEWS5
-rw-r--r--src/bytecode.c14
-rw-r--r--src/data.c86
-rw-r--r--test/src/data-tests.el6
4 files changed, 70 insertions, 41 deletions
diff --git a/etc/NEWS b/etc/NEWS
index 5b5baff44e1..17353936e7f 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -902,6 +902,11 @@ interpreting consecutive runs of numerical characters as numbers, and
902compares their numerical values. According to this predicate, 902compares 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
907internal rounding errors. For example, (< most-positive-fixnum (+ 1.0
908most-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
907to the corresponding character code. 912to 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
2394Lisp_Object 2394Lisp_Object
2395arithcompare (Lisp_Object num1, Lisp_Object num2, enum Arith_Comparison comparison) 2395arithcompare (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
2447static Lisp_Object 2472static Lisp_Object
2448arithcompare_driver (ptrdiff_t nargs, Lisp_Object *args, 2473arithcompare_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