Subject: (/ N) should return the reciprocal of N

From: Paul Eggert <[email-masked]>
Date: Thu, 15 Oct 2015 12:11:03 -0700

Tags: patch

The attached proposed patch is a followup to the recent discussion on 
emacs-devel. We're in feature-freeze now, so it's not a good time to 
apply it. Although I'm sympathetic to Stefan's point that the Common 
Lisp behavior is less logical, it is more useful in practice (as can be 
seen from some uses in the proposed patch) and there is a benefit to 
being compatible with CL.

>From b512e3a7a814eba4f09c11c3aad6d96ea6d0ae7c Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email-masked]>
Date: Thu, 15 Oct 2015 12:05:35 -0700
Subject: [PATCH] (/ N) now returns the reciprocal of N
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This is more compatible with Common Lisp and with XEmacs.  See:
http://lists.gnu.org/archive/html/emacs-devel/2015-10/msg01053.html
* lisp/color.el (color-hue-to-rgb, color-hsl-to-rgb)
(color-xyz-to-srgb, color-xyz-to-lab):
* lisp/emacs-lisp/cl-extra.el (cl-float-limits):
* lisp/net/shr-color.el (shr-color-hue-to-rgb)
(shr-color-hsl-to-rgb-fractions):
Exploit the change to simplify the code a bit.
* lisp/emacs-lisp/bytecomp.el (byte-compile-quo):
Don’t complain about single-argument calls to ‘/’.
* src/data.c (arith_driver, float_arith_driver):
Implement the change.
---
 doc/lispref/numbers.texi    | 17 +++++++++++++----
 etc/NEWS                    |  6 ++++++
 lisp/color.el               | 18 +++++++++---------
 lisp/emacs-lisp/bytecomp.el |  4 ++--
 lisp/emacs-lisp/cl-extra.el |  2 +-
 lisp/net/shr-color.el       |  6 +++---
 src/data.c                  | 11 +++++++----
 7 files changed, 41 insertions(+), 23 deletions(-)

diff --git a/doc/lispref/numbers.texi b/doc/lispref/numbers.texi
index 3c70d2f..54c8d3e 100644
--- a/doc/lispref/numbers.texi
+++ b/doc/lispref/numbers.texi
@@ -642,10 +642,11 @@ Arithmetic Operations
 @end example
 @end defun
 
-@defun / dividend divisor &rest divisors
-This function divides @var{dividend} by @var{divisor} and returns the
-quotient.  If there are additional arguments @var{divisors}, then it
-divides @var{dividend} by each divisor in turn.  Each argument may be a
+@defun / number &rest divisors
+With one or more @var{divisors}, this function divides @var{number}
+by each divisor in @var{divisors} in turn, and returns the quotient.
+With no @var{divisors}, this function returns 1/@var{number}, i.e.,
+the multiplicative inverse of @var{number}.  Each argument may be a
 number or a marker.
 
 If all the arguments are integers, the result is an integer, obtained
@@ -673,6 +674,14 @@ Arithmetic Operations
      @result{} 2.5
 @end group
 @group
+(/ 4.0)
+     @result{} 0.25
+@end group
+@group
+(/ 4)
+     @result{} 0
+@end group
+@group
 (/ 25 3 2)
      @result{} 4
 @end group
diff --git a/etc/NEWS b/etc/NEWS
index dbe0de3..8170c4a 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1007,6 +1007,12 @@ dynamically.
 dynamically.  Any third-party code that changes these templates should
 be updated accordingly.
 
++++
+** ‘(/ N)’ is now equivalent to ‘(/ 1 N)’ rather than to ‘(/ N 1)’.
+The new behavior is compatible with Common Lisp and with XEmacs.
+This change does not affect Lisp code intended to be portable to
+Emacs 24.2 and earlier, which did not support unary ‘/’.
+
 
 * Lisp Changes in Emacs 25.1
 
diff --git a/lisp/color.el b/lisp/color.el
index d572222..97656ca 100644
--- a/lisp/color.el
+++ b/lisp/color.el
@@ -93,7 +93,7 @@ color-hue-to-rgb
   "Compute hue from V1 and V2 H.
 Used internally by `color-hsl-to-rgb'."
   (cond
-   ((< h (/ 1.0 6))   (+ v1 (* (- v2 v1) h 6.0)))
+   ((< h (/ 6.0))     (+ v1 (* (- v2 v1) h 6.0)))
    ((< h 0.5)         v2)
    ((< h (/ 2.0 3))   (+ v1 (* (- v2 v1) (- (/ 2.0 3) h) 6.0)))
    (t                 v1)))
@@ -110,9 +110,9 @@ color-hsl-to-rgb
 		 (- (+ L S) (* L S))))
 	   (m1 (- (* 2.0 L) m2)))
       (list
-       (color-hue-to-rgb m1 m2 (mod (+ H (/ 1.0 3)) 1))
+       (color-hue-to-rgb m1 m2 (mod (+ H (/ 3.0)) 1))
        (color-hue-to-rgb m1 m2 H)
-       (color-hue-to-rgb m1 m2 (mod (- H (/ 1.0 3)) 1))))))
+       (color-hue-to-rgb m1 m2 (mod (- H (/ 3.0)) 1))))))
 
 (defun color-complement-hex (color)
   "Return the color that is the complement of COLOR, in hexadecimal format."
@@ -199,13 +199,13 @@ color-xyz-to-srgb
         (b (+ (* 0.0556434 X) (* -0.2040259 Y) (* 1.0572252 Z))))
     (list (if (<= r 0.0031308)
               (* 12.92 r)
-            (- (* 1.055 (expt r (/ 1 2.4))) 0.055))
+            (- (* 1.055 (expt r (/ 2.4))) 0.055))
           (if (<= g 0.0031308)
               (* 12.92 g)
-            (- (* 1.055 (expt g (/ 1 2.4))) 0.055))
+            (- (* 1.055 (expt g (/ 2.4))) 0.055))
           (if (<= b 0.0031308)
               (* 12.92 b)
-            (- (* 1.055 (expt b (/ 1 2.4))) 0.055)))))
+            (- (* 1.055 (expt b (/ 2.4))) 0.055)))))
 
 (defconst color-d65-xyz '(0.950455 1.0 1.088753)
   "D65 white point in CIE XYZ.")
@@ -222,13 +222,13 @@ color-xyz-to-lab
              (yr (/ Y Yr))
              (zr (/ Z Zr))
              (fx (if (> xr color-cie-ε)
-                     (expt xr (/ 1 3.0))
+                     (expt xr (/ 3.0))
                    (/ (+ (* color-cie-κ xr) 16) 116.0)))
              (fy (if (> yr color-cie-ε)
-                     (expt yr (/ 1 3.0))
+                     (expt yr (/ 3.0))
                    (/ (+ (* color-cie-κ yr) 16) 116.0)))
              (fz (if (> zr color-cie-ε)
-                     (expt zr (/ 1 3.0))
+                     (expt zr (/ 3.0))
                    (/ (+ (* color-cie-κ zr) 16) 116.0))))
         (list
          (- (* 116 fy) 16)                  ; L
diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el
index 6f7ba33..d138eff 100644
--- a/lisp/emacs-lisp/bytecomp.el
+++ b/lisp/emacs-lisp/bytecomp.el
@@ -3617,8 +3617,8 @@ byte-compile-minus
 
 (defun byte-compile-quo (form)
   (let ((len (length form)))
-    (cond ((<= len 2)
-	   (byte-compile-subr-wrong-args form "2 or more"))
+    (cond ((< len 2)
+	   (byte-compile-subr-wrong-args form "1 or more"))
 	  ((= len 3)
 	   (byte-compile-two-args form))
 	  (t
diff --git a/lisp/emacs-lisp/cl-extra.el b/lisp/emacs-lisp/cl-extra.el
index dddfca7..afa021d 100644
--- a/lisp/emacs-lisp/cl-extra.el
+++ b/lisp/emacs-lisp/cl-extra.el
@@ -497,7 +497,7 @@ cl-float-limits
 	(setq cl-least-positive-normalized-float y
 	      cl-least-negative-normalized-float (- y))
 	;; Divide down until value underflows to zero.
-	(setq x (/ 1 z) y x)
+	(setq x (/ z) y x)
 	(while (condition-case _ (> (/ x 2) 0) (arith-error nil))
 	  (setq x (/ x 2)))
 	(setq cl-least-positive-float x
diff --git a/lisp/net/shr-color.el b/lisp/net/shr-color.el
index 482f829..f8d358c 100644
--- a/lisp/net/shr-color.el
+++ b/lisp/net/shr-color.el
@@ -211,7 +211,7 @@ shr-color-hue-to-rgb
   "Convert X Y H to RGB value."
   (when (< h 0) (incf h))
   (when (> h 1) (decf h))
-  (cond ((< h (/ 1 6.0)) (+ x (* (- y x) h 6)))
+  (cond ((< h (/ 6.0)) (+ x (* (- y x) h 6)))
         ((< h 0.5) y)
         ((< h (/ 2.0 3.0)) (+ x (* (- y x) (- (/ 2.0 3.0) h) 6)))
         (t x)))
@@ -223,9 +223,9 @@ shr-color-hsl-to-rgb-fractions
         (setq m2 (* l (+ s 1)))
         (setq m2 (- (+ l s) (* l s))))
     (setq m1 (- (* l 2) m2))
-    (list (shr-color-hue-to-rgb m1 m2 (+ h (/ 1 3.0)))
+    (list (shr-color-hue-to-rgb m1 m2 (+ h (/ 3.0)))
 	  (shr-color-hue-to-rgb m1 m2 h)
-	  (shr-color-hue-to-rgb m1 m2 (- h (/ 1 3.0))))))
+	  (shr-color-hue-to-rgb m1 m2 (- h (/ 3.0))))))
 
 (defun shr-color->hexadecimal (color)
   "Convert any color format to hexadecimal representation.
diff --git a/src/data.c b/src/data.c
index b85d8a7..33fe285 100644
--- a/src/data.c
+++ b/src/data.c
@@ -2603,6 +2603,7 @@ arith_driver (enum arithop code, ptrdiff_t nargs, Lisp_Object *args)
       accum = 0;
       break;
     case Amult:
+    case Adiv:
       accum = 1;
       break;
     case Alogand:
@@ -2658,7 +2659,7 @@ arith_driver (enum arithop code, ptrdiff_t nargs, Lisp_Object *args)
 	    accum *= next;
 	  break;
 	case Adiv:
-	  if (!argnum)
+	  if (! (argnum || nargs == 1))
 	    accum = next;
 	  else
 	    {
@@ -2727,7 +2728,7 @@ float_arith_driver (double accum, ptrdiff_t argnum, enum arithop code,
 	  accum *= next;
 	  break;
 	case Adiv:
-	  if (!argnum)
+	  if (! (argnum || nargs == 1))
 	    accum = next;
 	  else
 	    {
@@ -2782,9 +2783,11 @@ usage: (* &rest NUMBERS-OR-MARKERS)  */)
 }
 
 DEFUN ("/", Fquo, Squo, 1, MANY, 0,
-       doc: /* Return first argument divided by all the remaining arguments.
+       doc: /* Divide number by divisors and return the result.
+With two or more arguments, return first argument divided by the rest.
+With one argument, return 1 divided by the argument.
 The arguments must be numbers or markers.
-usage: (/ DIVIDEND &rest DIVISORS)  */)
+usage: (/ NUMBER &rest DIVISORS)  */)
   (ptrdiff_t nargs, Lisp_Object *args)
 {
   ptrdiff_t argnum;
-- 
2.1.0