diff options
| author | Paul Eggert | 2017-03-06 15:14:32 -0800 |
|---|---|---|
| committer | Paul Eggert | 2017-03-06 17:26:55 -0800 |
| commit | 37940b347052418f0589bd52b06e56fffb594ea2 (patch) | |
| tree | 40d63a87959ed1afa9b0dad7a2cabb5cdbe88121 | |
| parent | 3bd2e9e975ed29daaf03ca7559e4664aade0674f (diff) | |
| download | emacs-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.texi | 6 | ||||
| -rw-r--r-- | etc/NEWS | 7 | ||||
| -rw-r--r-- | src/data.c | 43 | ||||
| -rw-r--r-- | test/src/data-tests.el | 20 |
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 |
| 429 | This function returns the largest of its arguments. | 429 | This function returns the largest of its arguments. |
| 430 | If any of the arguments is floating point, the value is returned | ||
| 431 | as 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 |
| 444 | This function returns the smallest of its arguments. | 442 | This function returns the smallest of its arguments. |
| 445 | If any of the arguments is floating point, the value is returned | ||
| 446 | as floating point, even if it was given as an integer. | ||
| 447 | 443 | ||
| 448 | @example | 444 | @example |
| 449 | (min -4 1) | 445 | (min -4 1) |
| @@ -803,6 +803,13 @@ Unicode horizontal whitespace as defined in the Unicode Technical | |||
| 803 | Standard #18. If you only want to match space and tab, use [ \t] | 803 | Standard #18. If you only want to match space and tab, use [ \t] |
| 804 | instead. | 804 | instead. |
| 805 | 805 | ||
| 806 | +++ | ||
| 807 | ** 'min' and 'max' now always return one of their arguments. | ||
| 808 | Formerly, they returned a floating-point value if any argument was | ||
| 809 | floating-point, which was sometimes numerically incorrect. For | ||
| 810 | example, (min most-positive-fixnum (+ 1.0 most-positive-fixnum)) now | ||
| 811 | always 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 | ||
| 2727 | static Lisp_Object float_arith_driver (double, ptrdiff_t, enum arithop, | 2725 | static 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 | ||
| 2960 | static Lisp_Object | ||
| 2961 | minmax_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 | |||
| 2978 | DEFUN ("max", Fmax, Smax, 1, MANY, 0, | 2977 | DEFUN ("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). |
| 2980 | The value is always a number; markers are converted to numbers. | ||
| 2981 | usage: (max NUMBER-OR-MARKER &rest NUMBERS-OR-MARKERS) */) | 2979 | usage: (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 | ||
| 2987 | DEFUN ("min", Fmin, Smin, 1, MANY, 0, | 2985 | DEFUN ("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). |
| 2989 | The value is always a number; markers are converted to numbers. | ||
| 2990 | usage: (min NUMBER-OR-MARKER &rest NUMBERS-OR-MARKERS) */) | 2987 | usage: (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 | ||
| 2996 | DEFUN ("logand", Flogand, Slogand, 0, MANY, 0, | 2993 | DEFUN ("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 | ||