aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Eggert2017-03-06 15:14:32 -0800
committerPaul Eggert2017-03-06 17:26:55 -0800
commit37940b347052418f0589bd52b06e56fffb594ea2 (patch)
tree40d63a87959ed1afa9b0dad7a2cabb5cdbe88121
parent3bd2e9e975ed29daaf03ca7559e4664aade0674f (diff)
downloademacs-37940b347052418f0589bd52b06e56fffb594ea2.tar.gz
emacs-37940b347052418f0589bd52b06e56fffb594ea2.zip
min and max now return one of their arguments
* doc/lispref/numbers.texi (Comparison of Numbers): * etc/NEWS: Document this. * src/data.c (Amax, Amin): Remove constants. All uses removed. (minmax_driver): New function. (Fmax, Fmin): Use it instead of arith_driver. * test/src/data-tests.el (data-tests-max, data-tests-min): New tests.
-rw-r--r--doc/lispref/numbers.texi6
-rw-r--r--etc/NEWS7
-rw-r--r--src/data.c43
-rw-r--r--test/src/data-tests.el20
4 files changed, 48 insertions, 28 deletions
diff --git a/doc/lispref/numbers.texi b/doc/lispref/numbers.texi
index deae5fd85dc..3fdc94169bd 100644
--- a/doc/lispref/numbers.texi
+++ b/doc/lispref/numbers.texi
@@ -427,8 +427,6 @@ the following argument. It returns @code{t} if so, @code{nil} otherwise.
427 427
428@defun max number-or-marker &rest numbers-or-markers 428@defun max number-or-marker &rest numbers-or-markers
429This function returns the largest of its arguments. 429This function returns the largest of its arguments.
430If any of the arguments is floating point, the value is returned
431as floating point, even if it was given as an integer.
432 430
433@example 431@example
434(max 20) 432(max 20)
@@ -436,14 +434,12 @@ as floating point, even if it was given as an integer.
436(max 1 2.5) 434(max 1 2.5)
437 @result{} 2.5 435 @result{} 2.5
438(max 1 3 2.5) 436(max 1 3 2.5)
439 @result{} 3.0 437 @result{} 3
440@end example 438@end example
441@end defun 439@end defun
442 440
443@defun min number-or-marker &rest numbers-or-markers 441@defun min number-or-marker &rest numbers-or-markers
444This function returns the smallest of its arguments. 442This function returns the smallest of its arguments.
445If any of the arguments is floating point, the value is returned
446as floating point, even if it was given as an integer.
447 443
448@example 444@example
449(min -4 1) 445(min -4 1)
diff --git a/etc/NEWS b/etc/NEWS
index 8f7356f3e03..ce20dfb15d7 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -803,6 +803,13 @@ Unicode horizontal whitespace as defined in the Unicode Technical
803Standard #18. If you only want to match space and tab, use [ \t] 803Standard #18. If you only want to match space and tab, use [ \t]
804instead. 804instead.
805 805
806+++
807** 'min' and 'max' now always return one of their arguments.
808Formerly, they returned a floating-point value if any argument was
809floating-point, which was sometimes numerically incorrect. For
810example, (min most-positive-fixnum (+ 1.0 most-positive-fixnum)) now
811always returns its first argument instead of its second.
812
806 813
807* Lisp Changes in Emacs 26.1 814* Lisp Changes in Emacs 26.1
808 815
diff --git a/src/data.c b/src/data.c
index 66f4c9c738d..ae88e3f8aa5 100644
--- a/src/data.c
+++ b/src/data.c
@@ -2719,9 +2719,7 @@ enum arithop
2719 Adiv, 2719 Adiv,
2720 Alogand, 2720 Alogand,
2721 Alogior, 2721 Alogior,
2722 Alogxor, 2722 Alogxor
2723 Amax,
2724 Amin
2725 }; 2723 };
2726 2724
2727static Lisp_Object float_arith_driver (double, ptrdiff_t, enum arithop, 2725static Lisp_Object float_arith_driver (double, ptrdiff_t, enum arithop,
@@ -2807,14 +2805,6 @@ arith_driver (enum arithop code, ptrdiff_t nargs, Lisp_Object *args)
2807 case Alogxor: 2805 case Alogxor:
2808 accum ^= next; 2806 accum ^= next;
2809 break; 2807 break;
2810 case Amax:
2811 if (!argnum || next > accum)
2812 accum = next;
2813 break;
2814 case Amin:
2815 if (!argnum || next < accum)
2816 accum = next;
2817 break;
2818 } 2808 }
2819 } 2809 }
2820 2810
@@ -2871,14 +2861,6 @@ float_arith_driver (double accum, ptrdiff_t argnum, enum arithop code,
2871 case Alogior: 2861 case Alogior:
2872 case Alogxor: 2862 case Alogxor:
2873 wrong_type_argument (Qinteger_or_marker_p, val); 2863 wrong_type_argument (Qinteger_or_marker_p, val);
2874 case Amax:
2875 if (!argnum || isnan (next) || next > accum)
2876 accum = next;
2877 break;
2878 case Amin:
2879 if (!argnum || isnan (next) || next < accum)
2880 accum = next;
2881 break;
2882 } 2864 }
2883 } 2865 }
2884 2866
@@ -2975,22 +2957,37 @@ Both X and Y must be numbers or markers. */)
2975 return val; 2957 return val;
2976} 2958}
2977 2959
2960static Lisp_Object
2961minmax_driver (ptrdiff_t nargs, Lisp_Object *args,
2962 enum Arith_Comparison comparison)
2963{
2964 eassume (0 < nargs);
2965 Lisp_Object accum;
2966 for (ptrdiff_t argnum = 0; argnum < nargs; argnum++)
2967 {
2968 Lisp_Object val = args[argnum];
2969 if (argnum == 0 || !NILP (arithcompare (val, accum, comparison)))
2970 accum = val;
2971 else if (FLOATP (accum) && isnan (XFLOAT_DATA (accum)))
2972 break;
2973 }
2974 return accum;
2975}
2976
2978DEFUN ("max", Fmax, Smax, 1, MANY, 0, 2977DEFUN ("max", Fmax, Smax, 1, MANY, 0,
2979 doc: /* Return largest of all the arguments (which must be numbers or markers). 2978 doc: /* Return largest of all the arguments (which must be numbers or markers).
2980The value is always a number; markers are converted to numbers.
2981usage: (max NUMBER-OR-MARKER &rest NUMBERS-OR-MARKERS) */) 2979usage: (max NUMBER-OR-MARKER &rest NUMBERS-OR-MARKERS) */)
2982 (ptrdiff_t nargs, Lisp_Object *args) 2980 (ptrdiff_t nargs, Lisp_Object *args)
2983{ 2981{
2984 return arith_driver (Amax, nargs, args); 2982 return minmax_driver (nargs, args, ARITH_GRTR);
2985} 2983}
2986 2984
2987DEFUN ("min", Fmin, Smin, 1, MANY, 0, 2985DEFUN ("min", Fmin, Smin, 1, MANY, 0,
2988 doc: /* Return smallest of all the arguments (which must be numbers or markers). 2986 doc: /* Return smallest of all the arguments (which must be numbers or markers).
2989The value is always a number; markers are converted to numbers.
2990usage: (min NUMBER-OR-MARKER &rest NUMBERS-OR-MARKERS) */) 2987usage: (min NUMBER-OR-MARKER &rest NUMBERS-OR-MARKERS) */)
2991 (ptrdiff_t nargs, Lisp_Object *args) 2988 (ptrdiff_t nargs, Lisp_Object *args)
2992{ 2989{
2993 return arith_driver (Amin, nargs, args); 2990 return minmax_driver (nargs, args, ARITH_LESS);
2994} 2991}
2995 2992
2996DEFUN ("logand", Flogand, Slogand, 0, MANY, 0, 2993DEFUN ("logand", Flogand, Slogand, 0, MANY, 0,
diff --git a/test/src/data-tests.el b/test/src/data-tests.el
index d38760cdde6..70ffdabe4d4 100644
--- a/test/src/data-tests.el
+++ b/test/src/data-tests.el
@@ -80,6 +80,26 @@
80 ;; Short circuits before getting to bad arg 80 ;; Short circuits before getting to bad arg
81 (should-not (>= 8 9 'foo))) 81 (should-not (>= 8 9 'foo)))
82 82
83(ert-deftest data-tests-max ()
84 (should-error (max))
85 (should (= 1 (max 1)))
86 (should (= 3 (max 3 2)))
87 (should (= 666 (max 666 1 0 0 -2 -3 -3 -3 -4 -8 -8 -9 -999)))
88 (should (= (1+ most-negative-fixnum)
89 (max (float most-negative-fixnum) (1+ most-negative-fixnum))))
90 (should (= 8 (apply #'max '(3 8 3))))
91 (should-error (max 9 8 'foo)))
92
93(ert-deftest data-tests-min ()
94 (should-error (min))
95 (should (= 1 (min 1)))
96 (should (= 2 (min 3 2)))
97 (should (= -999 (min 666 1 0 0 -2 -3 -3 -3 -4 -8 -8 -9 -999)))
98 (should (= most-positive-fixnum
99 (min (+ 1.0 most-positive-fixnum) most-positive-fixnum)))
100 (should (= 3 (apply #'min '(3 8 3))))
101 (should-error (min 9 8 'foo)))
102
83;; Bool vector tests. Compactly represent bool vectors as hex 103;; Bool vector tests. Compactly represent bool vectors as hex
84;; strings. 104;; strings.
85 105