Simplify, document, and port floating-point.

The porting part of this patch fixes bugs on non-IEEE platforms
with frexp, ldexp, logb.
* admin/CPP-DEFINES (HAVE_CBRT, HAVE_LOGB, logb): Remove.
* configure.ac (logb, cbrt): Do not check for these functions,
as they are not being used.
* doc/lispref/numbers.texi (Float Basics, Arithmetic Operations, Math Functions):
Document that / and mod (with floating point arguments), along
with asin, acos, log, log10, expt and sqrt, return special values
instead of signaling exceptions.
(Float Basics): Document that logb operates on the absolute value
of its argument.
(Math Functions): Document that (log ARG BASE) also returns NaN if
BASE is negative.  Document that (expt X Y) returns NaN if X is a
finite negative number and Y a finite non-integer.
* etc/NEWS: Document NaNs versus signaling-error change.
* src/data.c, src/lisp.h (Qdomain_error, Qsingularity_error, Qunderflow_error):
Now static.
* src/floatfns.c: Simplify discussion of functions that Emacs doesn't
support, by removing commented-out code and briefly listing the
C89 functions excluded.  The commented-out stuff was confusing
maintenance, e.g., we thought we needed cbrt but it was commented out.
(logb): Remove decl; no longer needed.
(isfinite): New macro, if not already supplied.
(isnan): Don't replace any existing macro.
(Ffrexp, Fldexp): Define even if !HAVE_COPYSIGN, as frexp and ldexp
are present on all C89 platforms.
(Ffrexp): Do not special-case zero, as frexp does the right thing
for that case.
(Flogb): Do not use logb, as it doesn't have the desired meaning
on hosts that use non-base-2 floating point.  Instead, stick with
frexp, which is C89 anyway.  Do not pass an infinity or a NaN to
frexp, to avoid getting an unspecified result.
This commit is contained in:
Paul Eggert 2012-09-10 19:28:27 -07:00
parent 6fda35f2b3
commit c990426a98
12 changed files with 105 additions and 236 deletions

View file

@ -1,3 +1,9 @@
2012-09-11 Paul Eggert <eggert@cs.ucla.edu>
Simplify, document, and port floating-point (Bug#12381).
* configure.ac (logb, cbrt): Do not check for these functions,
as they are not being used.
2012-09-10 Paul Eggert <eggert@cs.ucla.edu>
Improve robustness of 'make bootstrap' (Bug#12376).

View file

@ -120,7 +120,6 @@ HAVE_ATTRIBUTE_ALIGNED
HAVE_BDFFONT
HAVE_BOXES
HAVE_C99_STRTOLD
HAVE_CBRT
HAVE_CFMAKERAW
HAVE_CFSETSPEED
HAVE_CLOCK_GETTIME
@ -251,7 +250,6 @@ HAVE_LIBXMU
HAVE_LINUX_VERSION_H
HAVE_LOCALTIME_R
HAVE_LOCAL_SOCKETS
HAVE_LOGB
HAVE_LONG_FILE_NAMES
HAVE_LONG_LONG_INT
HAVE_LRAND48
@ -574,7 +572,6 @@ getpid
isatty
kill
link
logb
lseek
mkdir
mktemp
@ -616,7 +613,6 @@ fopen
getpid
index
isatty
logb
lseek
mkdir
mktemp

View file

@ -1,3 +1,8 @@
2012-09-11 Paul Eggert <eggert@cs.ucla.edu>
Simplify, document, and port floating-point (Bug#12381).
* CPP-DEFINES (HAVE_CBRT, HAVE_LOGB, logb): Remove.
2012-09-09 Paul Eggert <eggert@cs.ucla.edu>
Assume C89 or later for math functions (Bug#12381).

View file

@ -2689,8 +2689,8 @@ if test $emacs_cv_netdb_declares_h_errno = yes; then
AC_DEFINE(HAVE_H_ERRNO, 1, [Define to 1 if netdb.h declares h_errno.])
fi
# fmod, logb, and frexp are found in -lm on most systems.
# On HPUX 9.01, -lm does not contain logb, so check for sqrt.
# sqrt and other floating-point functions such as fmod and frexp
# are found in -lm on most systems.
AC_CHECK_LIB(m, sqrt)
# Check for mail-locking functions in a "mail" library. Probably this should
@ -2770,7 +2770,7 @@ AC_SUBST(BLESSMAIL_TARGET)
AC_CHECK_FUNCS(gethostname \
closedir getrusage get_current_dir_name \
lrand48 logb cbrt setsid \
lrand48 setsid \
fpathconf select euidaccess getpagesize setlocale \
utimes getrlimit setrlimit setpgid getcwd shutdown getaddrinfo \
__fpending strsignal setitimer \

View file

@ -1,3 +1,16 @@
2012-09-11 Paul Eggert <eggert@cs.ucla.edu>
Simplify, document, and port floating-point (Bug#12381).
* numbers.texi (Float Basics, Arithmetic Operations, Math Functions):
Document that / and mod (with floating point arguments), along
with asin, acos, log, log10, expt and sqrt, return special values
instead of signaling exceptions.
(Float Basics): Document that logb operates on the absolute value
of its argument.
(Math Functions): Document that (log ARG BASE) also returns NaN if
BASE is negative. Document that (expt X Y) returns NaN if X is a
finite negative number and Y a finite non-integer.
2012-09-09 Chong Yidong <cyd@gnu.org>
* lists.texi (Sets And Lists): Explain that the return value for

View file

@ -196,6 +196,14 @@ numerical functions return such values in cases where there is no
correct answer. For example, @code{(/ 0.0 0.0)} returns a NaN. (NaN
values can also carry a sign, but for practical purposes there's no
significant difference between different NaN values in Emacs Lisp.)
When a function is documented to return a NaN, it returns an
implementation-defined value when Emacs is running on one of the
now-rare platforms that do not use @acronym{IEEE} floating point. For
example, @code{(log -1.0)} typically returns a NaN, but on
non-@acronym{IEEE} platforms it returns an implementation-defined
value.
Here are the read syntaxes for these special floating point values:
@table @asis
@ -241,7 +249,7 @@ numbers.
@defun logb number
This function returns the binary exponent of @var{number}. More
precisely, the value is the logarithm of @var{number} base 2, rounded
precisely, the value is the logarithm of |@var{number}| base 2, rounded
down to an integer.
@example
@ -694,7 +702,8 @@ arguments. It also permits floating point arguments; it rounds the
quotient downward (towards minus infinity) to an integer, and uses that
quotient to compute the remainder.
An @code{arith-error} results if @var{divisor} is 0.
If @var{divisor} is zero, @code{mod} signals an @code{arith-error}
error if both arguments are integers, and returns a NaN otherwise.
@example
@group
@ -1096,8 +1105,8 @@ pi/2
@tex
@math{\pi/2}
@end tex
(inclusive) whose sine is @var{arg}; if, however, @var{arg} is out of
range (outside [@minus{}1, 1]), it signals a @code{domain-error} error.
(inclusive) whose sine is @var{arg}. If @var{arg} is out of range
(outside [@minus{}1, 1]), @code{asin} returns a NaN.
@end defun
@defun acos arg
@ -1108,8 +1117,8 @@ pi
@tex
@math{\pi}
@end tex
(inclusive) whose cosine is @var{arg}; if, however, @var{arg} is out
of range (outside [@minus{}1, 1]), it signals a @code{domain-error} error.
(inclusive) whose cosine is @var{arg}. If @var{arg} is out of range
(outside [@minus{}1, 1]), @code{acos} returns a NaN.
@end defun
@defun atan y &optional x
@ -1141,8 +1150,8 @@ This is the exponential function; it returns @math{e} to the power
@defun log arg &optional base
This function returns the logarithm of @var{arg}, with base
@var{base}. If you don't specify @var{base}, the natural base
@math{e} is used. If @var{arg} is negative, it signals a
@code{domain-error} error.
@math{e} is used. If @var{arg} or @var{base} is negative, @code{log}
returns a NaN.
@end defun
@ignore
@ -1160,21 +1169,21 @@ lose accuracy.
@end ignore
@defun log10 arg
This function returns the logarithm of @var{arg}, with base 10. If
@var{arg} is negative, it signals a @code{domain-error} error.
@code{(log10 @var{x})} @equiv{} @code{(log @var{x} 10)}, at least
approximately.
This function returns the logarithm of @var{arg}, with base 10:
@code{(log10 @var{x})} @equiv{} @code{(log @var{x} 10)}.
@end defun
@defun expt x y
This function returns @var{x} raised to power @var{y}. If both
arguments are integers and @var{y} is positive, the result is an
integer; in this case, overflow causes truncation, so watch out.
If @var{x} is a finite negative number and @var{y} is a finite
non-integer, @code{expt} returns a NaN.
@end defun
@defun sqrt arg
This returns the square root of @var{arg}. If @var{arg} is negative,
it signals a @code{domain-error} error.
@code{sqrt} returns a NaN.
@end defun
In addition, Emacs defines the following common mathematical

View file

@ -1,3 +1,8 @@
2012-09-11 Paul Eggert <eggert@cs.ucla.edu>
Simplify, document, and port floating-point (Bug#12381).
* NEWS: Document NaNs versus signaling-error change.
2012-09-04 Paul Eggert <eggert@cs.ucla.edu>
Give more-useful info on a fatal error (Bug#12328).

View file

@ -729,6 +729,14 @@ table, but with a different prefix.
must be in the range 1000..9999. It now works with any year supported
by the underlying C implementation.
** Floating point
*** When floating point functions such as `log' are given invalid
arguments, e.g., (log -1.0), they now uniformly return special values
such as NaNs instead of signaling errors. Previously, these functions
returned NaNs on some platforms but signaled errors on others. The affected
functions are acos, asin, tan, exp, expt, log, log10, sqrt, and mod.
** New function file-name-base.
** New function `tty-top-frame' returns the topmost frame of a text terminal.

View file

@ -1,5 +1,26 @@
2012-09-11 Paul Eggert <eggert@cs.ucla.edu>
Simplify, document, and port floating-point (Bug#12381).
The porting part of this patch fixes bugs on non-IEEE platforms
with frexp, ldexp, logb.
* data.c, lisp.h (Qdomain_error, Qsingularity_error, Qunderflow_error):
Now static.
* floatfns.c: Simplify discussion of functions that Emacs doesn't
support, by removing commented-out code and briefly listing the
C89 functions excluded. The commented-out stuff was confusing
maintenance, e.g., we thought we needed cbrt but it was commented out.
(logb): Remove decl; no longer needed.
(isfinite): New macro, if not already supplied.
(isnan): Don't replace any existing macro.
(Ffrexp, Fldexp): Define even if !HAVE_COPYSIGN, as frexp and ldexp
are present on all C89 platforms.
(Ffrexp): Do not special-case zero, as frexp does the right thing
for that case.
(Flogb): Do not use logb, as it doesn't have the desired meaning
on hosts that use non-base-2 floating point. Instead, stick with
frexp, which is C89 anyway. Do not pass an infinity or a NaN to
frexp, to avoid getting an unspecified result.
* xdisp.c (Qinhibit_debug_on_message): Now static.
2012-09-10 Jan Djärv <jan.h.d@swipnet.se>

View file

@ -71,8 +71,8 @@ Lisp_Object Qchar_table_p, Qvector_or_char_table_p;
Lisp_Object Qcdr;
static Lisp_Object Qad_advice_info, Qad_activate_internal;
Lisp_Object Qrange_error, Qdomain_error, Qsingularity_error;
Lisp_Object Qoverflow_error, Qunderflow_error;
static Lisp_Object Qdomain_error, Qsingularity_error, Qunderflow_error;
Lisp_Object Qrange_error, Qoverflow_error;
Lisp_Object Qfloatp;
Lisp_Object Qnumberp, Qnumber_or_marker_p;

View file

@ -22,9 +22,10 @@ You should have received a copy of the GNU General Public License
along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
/* C89 requires only these math.h functions:
acos, asin, atan, atan2, ceil, cos, cosh, exp, fabs, floor, fmod,
frexp, ldexp, log, log10, modf, pow, sin, sinh, sqrt, tan, tanh.
/* C89 requires only the following math.h functions, and Emacs omits
the starred functions since we haven't found a use for them:
acos, asin, atan, atan2, ceil, cos, *cosh, exp, fabs, floor, fmod,
frexp, ldexp, log, log10, *modf, pow, sin, *sinh, sqrt, tan, *tanh.
*/
#include <config.h>
@ -42,10 +43,12 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#include <math.h>
/* This declaration is omitted on some systems, like Ultrix. */
#if !defined (HPUX) && defined (HAVE_LOGB) && !defined (logb)
extern double logb (double);
#endif /* not HPUX and HAVE_LOGB and no logb macro */
#ifndef isfinite
# define isfinite(x) ((x) - (x) == 0)
#endif
#ifndef isnan
# define isnan(x) ((x) != (x))
#endif
/* Extract a Lisp number as a `double', or signal an error. */
@ -126,9 +129,6 @@ DEFUN ("tan", Ftan, Stan, 1, 1, 0,
return make_float (d);
}
#undef isnan
#define isnan(x) ((x) != (x))
DEFUN ("isnan", Fisnan, Sisnan, 1, 1, 0,
doc: /* Return non nil iff argument X is a NaN. */)
(Lisp_Object x)
@ -153,6 +153,7 @@ Cause an error if X1 or X2 is not a float. */)
return make_float (copysign (f1, f2));
}
#endif
DEFUN ("frexp", Ffrexp, Sfrexp, 1, 1, 0,
doc: /* Get significand and exponent of a floating point number.
@ -167,15 +168,9 @@ If X is zero, both parts (SGNFCAND and EXP) are zero. */)
(Lisp_Object x)
{
double f = XFLOATINT (x);
if (f == 0.0)
return Fcons (make_float (0.0), make_number (0));
else
{
int exponent;
double sgnfcand = frexp (f, &exponent);
return Fcons (make_float (sgnfcand), make_number (exponent));
}
int exponent;
double sgnfcand = frexp (f, &exponent);
return Fcons (make_float (sgnfcand), make_number (exponent));
}
DEFUN ("ldexp", Fldexp, Sldexp, 1, 2, 0,
@ -187,118 +182,6 @@ Returns the floating point value resulting from multiplying SGNFCAND
CHECK_NUMBER (exponent);
return make_float (ldexp (XFLOATINT (sgnfcand), XINT (exponent)));
}
#endif
#if 0 /* Leave these out unless we find there's a reason for them. */
DEFUN ("bessel-j0", Fbessel_j0, Sbessel_j0, 1, 1, 0,
doc: /* Return the bessel function j0 of ARG. */)
(Lisp_Object arg)
{
double d = extract_float (arg);
d = j0 (d);
return make_float (d);
}
DEFUN ("bessel-j1", Fbessel_j1, Sbessel_j1, 1, 1, 0,
doc: /* Return the bessel function j1 of ARG. */)
(Lisp_Object arg)
{
double d = extract_float (arg);
d = j1 (d);
return make_float (d);
}
DEFUN ("bessel-jn", Fbessel_jn, Sbessel_jn, 2, 2, 0,
doc: /* Return the order N bessel function output jn of ARG.
The first arg (the order) is truncated to an integer. */)
(Lisp_Object n, Lisp_Object arg)
{
int i1 = extract_float (n);
double f2 = extract_float (arg);
f2 = jn (i1, f2);
return make_float (f2);
}
DEFUN ("bessel-y0", Fbessel_y0, Sbessel_y0, 1, 1, 0,
doc: /* Return the bessel function y0 of ARG. */)
(Lisp_Object arg)
{
double d = extract_float (arg);
d = y0 (d);
return make_float (d);
}
DEFUN ("bessel-y1", Fbessel_y1, Sbessel_y1, 1, 1, 0,
doc: /* Return the bessel function y1 of ARG. */)
(Lisp_Object arg)
{
double d = extract_float (arg);
d = y1 (d);
return make_float (d);
}
DEFUN ("bessel-yn", Fbessel_yn, Sbessel_yn, 2, 2, 0,
doc: /* Return the order N bessel function output yn of ARG.
The first arg (the order) is truncated to an integer. */)
(Lisp_Object n, Lisp_Object arg)
{
int i1 = extract_float (n);
double f2 = extract_float (arg);
f2 = yn (i1, f2);
return make_float (f2);
}
#endif
#if 0 /* Leave these out unless we see they are worth having. */
DEFUN ("erf", Ferf, Serf, 1, 1, 0,
doc: /* Return the mathematical error function of ARG. */)
(Lisp_Object arg)
{
double d = extract_float (arg);
d = erf (d);
return make_float (d);
}
DEFUN ("erfc", Ferfc, Serfc, 1, 1, 0,
doc: /* Return the complementary error function of ARG. */)
(Lisp_Object arg)
{
double d = extract_float (arg);
d = erfc (d);
return make_float (d);
}
DEFUN ("log-gamma", Flog_gamma, Slog_gamma, 1, 1, 0,
doc: /* Return the log gamma of ARG. */)
(Lisp_Object arg)
{
double d = extract_float (arg);
d = lgamma (d);
return make_float (d);
}
DEFUN ("cube-root", Fcube_root, Scube_root, 1, 1, 0,
doc: /* Return the cube root of ARG. */)
(Lisp_Object arg)
{
double d = extract_float (arg);
#ifdef HAVE_CBRT
d = cbrt (d);
#else
if (d >= 0.0)
d = pow (d, 1.0/3.0);
else
d = -pow (-d, 1.0/3.0);
#endif
return make_float (d);
}
#endif
DEFUN ("exp", Fexp, Sexp, 1, 1, 0,
doc: /* Return the exponential base e of ARG. */)
@ -383,63 +266,6 @@ DEFUN ("sqrt", Fsqrt, Ssqrt, 1, 1, 0,
return make_float (d);
}
#if 0 /* Not clearly worth adding. */
DEFUN ("acosh", Facosh, Sacosh, 1, 1, 0,
doc: /* Return the inverse hyperbolic cosine of ARG. */)
(Lisp_Object arg)
{
double d = extract_float (arg);
d = acosh (d);
return make_float (d);
}
DEFUN ("asinh", Fasinh, Sasinh, 1, 1, 0,
doc: /* Return the inverse hyperbolic sine of ARG. */)
(Lisp_Object arg)
{
double d = extract_float (arg);
d = asinh (d);
return make_float (d);
}
DEFUN ("atanh", Fatanh, Satanh, 1, 1, 0,
doc: /* Return the inverse hyperbolic tangent of ARG. */)
(Lisp_Object arg)
{
double d = extract_float (arg);
d = atanh (d);
return make_float (d);
}
DEFUN ("cosh", Fcosh, Scosh, 1, 1, 0,
doc: /* Return the hyperbolic cosine of ARG. */)
(Lisp_Object arg)
{
double d = extract_float (arg);
d = cosh (d);
return make_float (d);
}
DEFUN ("sinh", Fsinh, Ssinh, 1, 1, 0,
doc: /* Return the hyperbolic sine of ARG. */)
(Lisp_Object arg)
{
double d = extract_float (arg);
d = sinh (d);
return make_float (d);
}
DEFUN ("tanh", Ftanh, Stanh, 1, 1, 0,
doc: /* Return the hyperbolic tangent of ARG. */)
(Lisp_Object arg)
{
double d = extract_float (arg);
d = tanh (d);
return make_float (d);
}
#endif
DEFUN ("abs", Fabs, Sabs, 1, 1, 0,
doc: /* Return the absolute value of ARG. */)
(register Lisp_Object arg)
@ -477,16 +303,15 @@ This is the same as the exponent of a float. */)
if (f == 0.0)
value = MOST_NEGATIVE_FIXNUM;
else
else if (isfinite (f))
{
#ifdef HAVE_LOGB
value = logb (f);
#else
int ivalue;
frexp (f, &ivalue);
value = ivalue - 1;
#endif
}
else
value = MOST_POSITIVE_FIXNUM;
XSETINT (val, value);
return val;
}
@ -719,27 +544,9 @@ syms_of_floatfns (void)
defsubr (&Sisnan);
#ifdef HAVE_COPYSIGN
defsubr (&Scopysign);
#endif
defsubr (&Sfrexp);
defsubr (&Sldexp);
#endif
#if 0
defsubr (&Sacosh);
defsubr (&Sasinh);
defsubr (&Satanh);
defsubr (&Scosh);
defsubr (&Ssinh);
defsubr (&Stanh);
defsubr (&Sbessel_y0);
defsubr (&Sbessel_y1);
defsubr (&Sbessel_yn);
defsubr (&Sbessel_j0);
defsubr (&Sbessel_j1);
defsubr (&Sbessel_jn);
defsubr (&Serf);
defsubr (&Serfc);
defsubr (&Slog_gamma);
defsubr (&Scube_root);
#endif
defsubr (&Sfceiling);
defsubr (&Sffloor);
defsubr (&Sfround);

View file

@ -2559,8 +2559,7 @@ extern Lisp_Object Qchar_table_p, Qvector_or_char_table_p;
extern Lisp_Object Qcdr;
extern Lisp_Object Qrange_error, Qdomain_error, Qsingularity_error;
extern Lisp_Object Qoverflow_error, Qunderflow_error;
extern Lisp_Object Qrange_error, Qoverflow_error;
extern Lisp_Object Qfloatp;
extern Lisp_Object Qnumberp, Qnumber_or_marker_p;