From b6942c0c37a504e00c717c8c74bfa9dcd208c931 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sun, 10 Nov 2019 15:01:06 -0800 Subject: [PATCH] Document Lisp floats a bit better MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit * doc/lispref/numbers.texi (Float Basics): * doc/misc/cl.texi (Implementation Parameters): * lisp/emacs-lisp/cl-lib.el (cl-most-positive-float) (cl-least-positive-float) (cl-least-positive-normalized-float, cl-float-epsilon) (cl-float-negative-epsilon): Document IEEE floating point better. Don’t suggest that Emacs might use some floating-point format other than IEEE format, as Emacs currently assumes IEEE in several places and there seems little point in removing those assumptions. --- doc/lispref/numbers.texi | 8 ++++-- doc/misc/cl.texi | 54 +++++++++++++++++---------------------- lisp/emacs-lisp/cl-lib.el | 16 +++++------- 3 files changed, 37 insertions(+), 41 deletions(-) diff --git a/doc/lispref/numbers.texi b/doc/lispref/numbers.texi index 0c71387a8a7..939ad5c85a1 100644 --- a/doc/lispref/numbers.texi +++ b/doc/lispref/numbers.texi @@ -218,8 +218,12 @@ considered to be valid as a character. @xref{Character Codes}. Floating-point numbers are useful for representing numbers that are not integral. The range of floating-point numbers is the same as the range of the C data type @code{double} on the machine -you are using. On all computers currently supported by Emacs, this is -double-precision @acronym{IEEE} floating point. +you are using. On all computers supported by Emacs, this is +@acronym{IEEE} binary64 floating point format, which is standardized by +@url{https://standards.ieee.org/standard/754-2019.html,,IEEE Std 754-2019} +and is discussed further in David Goldberg's paper +``@url{https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html, +What Every Computer Scientist Should Know About Floating-Point Arithmetic}''. The read syntax for floating-point numbers requires either a decimal point, an exponent, or both. Optional signs (@samp{+} or @samp{-}) diff --git a/doc/misc/cl.texi b/doc/misc/cl.texi index 246f86bfd1a..cfdbc7c41b2 100644 --- a/doc/misc/cl.texi +++ b/doc/misc/cl.texi @@ -3113,48 +3113,42 @@ function that must be called before the parameters can be used. @defun cl-float-limits This function makes sure that the Common Lisp floating-point parameters like @code{cl-most-positive-float} have been initialized. Until it is -called, these parameters will be @code{nil}. -@c If this version of Emacs does not support floats, the parameters will -@c remain @code{nil}. +called, these parameters have unspecified values. If the parameters have already been initialized, the function returns immediately. - -The algorithm makes assumptions that will be valid for almost all -machines, but will fail if the machine's arithmetic is extremely -unusual, e.g., decimal. @end defun Since true Common Lisp supports up to four different kinds of floating-point numbers, it has families of constants like @code{most-positive-single-float}, @code{most-positive-double-float}, -@code{most-positive-long-float}, and so on. Emacs has only one -kind of floating-point number, so this package just uses single constants. +@code{most-positive-long-float}, and so on. This package uses just +one set of constants because Emacs has only one kind of +floating-point number, namely the IEEE binary64 floating-point format. +@xref{Float Basics,,,elisp,GNU Emacs Lisp Reference Manual}. @defvar cl-most-positive-float -This constant equals the largest value a Lisp float can hold. -For those systems whose arithmetic supports infinities, this is -the largest @emph{finite} value. For IEEE machines, the value -is approximately @code{1.79e+308}. +This constant equals the largest finite value a Lisp float can hold. +For IEEE binary64 format, this equals @code{(- (expt 2 1024) (- 2 +971))}, which equals @code{1.7976931348623157e+308}. @end defvar @defvar cl-most-negative-float -This constant equals the most negative value a Lisp float can hold. -(It is assumed to be equal to @code{(- cl-most-positive-float)}.) +This constant equals the most negative finite value a Lisp float can hold. +For IEEE binary64 format, this equals @code{(- cl-most-positive-float)}. @end defvar -@defvar cl-least-positive-float -This constant equals the smallest Lisp float value greater than zero. -For IEEE machines, it is about @code{4.94e-324} if denormals are -supported or @code{2.22e-308} if not. +@defvar cl-least-positive-normalized-float +This constant equals the smallest positive Lisp float that is +@dfn{normalized}, i.e., that has full precision. +For IEEE binary64 format, this equals @code{(expt 2 -1022)}, +which equals @code{2.2250738585072014e-308}. @end defvar -@defvar cl-least-positive-normalized-float -This constant equals the smallest @emph{normalized} Lisp float greater -than zero, i.e., the smallest value for which IEEE denormalization -will not result in a loss of precision. For IEEE machines, this -value is about @code{2.22e-308}. For machines that do not support -the concept of denormalization and gradual underflow, this constant -will always equal @code{cl-least-positive-float}. +@defvar cl-least-positive-float +This constant equals the smallest Lisp float value greater than zero. +For IEEE binary64 format, this equals @code{5e-324} (which equals +@code{(expt 2 -1074)}) if subnormal numbers are supported, and +@code{cl-least-positive-normalized-float} otherwise. @end defvar @defvar cl-least-negative-float @@ -3169,14 +3163,14 @@ This constant is the negative counterpart of @defvar cl-float-epsilon This constant is the smallest positive Lisp float that can be added to 1.0 to produce a distinct value. Adding a smaller number to 1.0 -will yield 1.0 again due to roundoff. For IEEE machines, epsilon -is about @code{2.22e-16}. +will yield 1.0 again due to roundoff. For IEEE binary64 format, this +equals @code{(expt 2 -52)}, which equals @code{2.220446049250313e-16}. @end defvar @defvar cl-float-negative-epsilon This is the smallest positive value that can be subtracted from -1.0 to produce a distinct value. For IEEE machines, it is about -@code{1.11e-16}. +1.0 to produce a distinct value. For IEEE binary64 format, this +equals @code{(expt 2 -53)}, which equals @code{1.1102230246251565e-16}. @end defvar @node Sequences diff --git a/lisp/emacs-lisp/cl-lib.el b/lisp/emacs-lisp/cl-lib.el index ff096918173..7d0df27e14b 100644 --- a/lisp/emacs-lisp/cl-lib.el +++ b/lisp/emacs-lisp/cl-lib.el @@ -299,7 +299,7 @@ If true return the decimal value of digit CHAR in RADIX." (defconst cl-most-positive-float nil "The largest value that a Lisp float can hold. If your system supports infinities, this is the largest finite value. -For IEEE machines, this is approximately 1.79e+308. +For Emacs, this equals 1.7976931348623157e+308. Call `cl-float-limits' to set this.") (defconst cl-most-negative-float nil @@ -309,8 +309,8 @@ Call `cl-float-limits' to set this.") (defconst cl-least-positive-float nil "The smallest value greater than zero that a Lisp float can hold. -For IEEE machines, it is about 4.94e-324 if denormals are supported, -or 2.22e-308 if they are not. +For Emacs, this equals 5e-324 if subnormal numbers are supported, +`cl-least-positive-normalized-float' if they are not. Call `cl-float-limits' to set this.") (defconst cl-least-negative-float nil @@ -320,10 +320,8 @@ Call `cl-float-limits' to set this.") (defconst cl-least-positive-normalized-float nil "The smallest normalized Lisp float greater than zero. -This is the smallest value for which IEEE denormalization does not lose -precision. For IEEE machines, this value is about 2.22e-308. -For machines that do not support the concept of denormalization -and gradual underflow, this constant equals `cl-least-positive-float'. +This is the smallest value that has full precision. +For Emacs, this equals 2.2250738585072014e-308. Call `cl-float-limits' to set this.") (defconst cl-least-negative-normalized-float nil @@ -334,12 +332,12 @@ Call `cl-float-limits' to set this.") (defconst cl-float-epsilon nil "The smallest positive float that adds to 1.0 to give a distinct value. Adding a number less than this to 1.0 returns 1.0 due to roundoff. -For IEEE machines, epsilon is about 2.22e-16. +For Emacs, this equals 2.220446049250313e-16. Call `cl-float-limits' to set this.") (defconst cl-float-negative-epsilon nil "The smallest positive float that subtracts from 1.0 to give a distinct value. -For IEEE machines, it is about 1.11e-16. +For Emacs, this equals 1.1102230246251565e-16. Call `cl-float-limits' to set this.") -- 2.39.5