/* Primitive operations on floating point for GNU Emacs Lisp interpreter.
-Copyright (C) 1988, 1993-1994, 1999, 2001-2013 Free Software Foundation,
+Copyright (C) 1988, 1993-1994, 1999, 2001-2016 Free Software Foundation,
Inc.
-Author: Wolfgang Rupprecht
-(according to ack.texi)
+Author: Wolfgang Rupprecht (according to ack.texi)
This file is part of GNU Emacs.
GNU Emacs is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
+the Free Software Foundation, either version 3 of the License, or (at
+your option) any later version.
GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
/* 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.
+ frexp, ldexp, log, log10 [via (log X 10)], *modf, pow, sin, *sinh,
+ sqrt, tan, *tanh.
+
+ C99 and C11 require the following math.h functions in addition to
+ the C89 functions. Of these, Emacs currently exports only the
+ starred ones to Lisp, since we haven't found a use for the others:
+ acosh, atanh, cbrt, *copysign, erf, erfc, exp2, expm1, fdim, fma,
+ fmax, fmin, fpclassify, hypot, ilogb, isfinite, isgreater,
+ isgreaterequal, isinf, isless, islessequal, islessgreater, *isnan,
+ isnormal, isunordered, lgamma, log1p, *log2 [via (log X 2)], *logb
+ (approximately), lrint/llrint, lround/llround, nan, nearbyint,
+ nextafter, nexttoward, remainder, remquo, *rint, round, scalbln,
+ scalbn, signbit, tgamma, trunc.
*/
#include <config.h>
#include <math.h>
-#ifndef isfinite
-# define isfinite(x) ((x) - (x) == 0)
-#endif
-#ifndef isnan
-# define isnan(x) ((x) != (x))
-#endif
+/* 'isfinite' and 'isnan' cause build failures on Solaris 10 with the
+ bundled GCC in c99 mode. Work around the bugs with simple
+ implementations that are good enough. */
+#undef isfinite
+#define isfinite(x) ((x) - (x) == 0)
+#undef isnan
+#define isnan(x) ((x) != (x))
+
+/* Check that X is a floating point number. */
+
+static void
+CHECK_FLOAT (Lisp_Object x)
+{
+ CHECK_TYPE (FLOATP (x), Qfloatp, x);
+}
/* Extract a Lisp number as a `double', or signal an error. */
}
DEFUN ("isnan", Fisnan, Sisnan, 1, 1, 0,
- doc: /* Return non nil iff argument X is a NaN. */)
+ doc: /* Return non nil if argument X is a NaN. */)
(Lisp_Object x)
{
CHECK_FLOAT (x);
return Fcons (make_float (sgnfcand), make_number (exponent));
}
-DEFUN ("ldexp", Fldexp, Sldexp, 1, 2, 0,
- doc: /* Construct number X from significand SGNFCAND and exponent EXP.
-Returns the floating point value resulting from multiplying SGNFCAND
-(the significand) by 2 raised to the power of EXP (the exponent). */)
+DEFUN ("ldexp", Fldexp, Sldexp, 2, 2, 0,
+ doc: /* Return X * 2**EXP, as a floating point number.
+EXP must be an integer. */)
(Lisp_Object sgnfcand, Lisp_Object exponent)
{
CHECK_NUMBER (exponent);
- return make_float (ldexp (XFLOATINT (sgnfcand), XINT (exponent)));
+ int e = min (max (INT_MIN, XINT (exponent)), INT_MAX);
+ return make_float (ldexp (XFLOATINT (sgnfcand), e));
}
\f
DEFUN ("exp", Fexp, Sexp, 1, 1, 0,
CHECK_NUMBER_OR_FLOAT (arg2);
if (INTEGERP (arg1) /* common lisp spec */
&& INTEGERP (arg2) /* don't promote, if both are ints, and */
- && 0 <= XINT (arg2)) /* we are sure the result is not fractional */
+ && XINT (arg2) >= 0) /* we are sure the result is not fractional */
{ /* this can be improved by pre-calculating */
EMACS_INT y; /* some binary powers of x then accumulating */
EMACS_UINT acc, x; /* Unsigned so that overflow is well defined. */
if (b == 10.0)
d = log10 (d);
+#if HAVE_LOG2
+ else if (b == 2.0)
+ d = log2 (d);
+#endif
else
d = log (d) / log (b);
}
return make_float (d);
}
-DEFUN ("log10", Flog10, Slog10, 1, 1, 0,
- doc: /* Return the logarithm base 10 of ARG. */)
- (Lisp_Object arg)
-{
- double d = extract_float (arg);
- d = log10 (d);
- return make_float (d);
-}
-
DEFUN ("sqrt", Fsqrt, Ssqrt, 1, 1, 0,
doc: /* Return the square root of ARG. */)
(Lisp_Object arg)
return arg;
}
-/* With C's /, the result is implementation-defined if either operand
- is negative, so take care with negative operands in the following
- integer functions. */
-
static EMACS_INT
ceiling2 (EMACS_INT i1, EMACS_INT i2)
{
- return (i2 < 0
- ? (i1 < 0 ? ((-1 - i1) / -i2) + 1 : - (i1 / -i2))
- : (i1 <= 0 ? - (-i1 / i2) : ((i1 - 1) / i2) + 1));
+ return i1 / i2 + ((i1 % i2 != 0) & ((i1 < 0) == (i2 < 0)));
}
static EMACS_INT
floor2 (EMACS_INT i1, EMACS_INT i2)
{
- return (i2 < 0
- ? (i1 <= 0 ? -i1 / -i2 : -1 - ((i1 - 1) / -i2))
- : (i1 < 0 ? -1 - ((-1 - i1) / i2) : i1 / i2));
+ return i1 / i2 - ((i1 % i2 != 0) & ((i1 < 0) != (i2 < 0)));
}
static EMACS_INT
truncate2 (EMACS_INT i1, EMACS_INT i2)
{
- return (i2 < 0
- ? (i1 < 0 ? -i1 / -i2 : - (i1 / -i2))
- : (i1 < 0 ? - (-i1 / i2) : i1 / i2));
+ return i1 / i2;
}
static EMACS_INT
static double
emacs_rint (double d)
{
- return floor (d + 0.5);
+ double d1 = d + 0.5;
+ double r = floor (d1);
+ return r - (r == d1 && fmod (r, 2) != 0);
}
#endif
Rounding a value equidistant between two integers may choose the
integer closer to zero, or it may prefer an even integer, depending on
-your machine. For example, \(round 2.5\) can return 3 on some
+your machine. For example, (round 2.5) can return 3 on some
systems, but 2 on others. */)
(Lisp_Object arg, Lisp_Object divisor)
{
f1 = fmod (f1, f2);
/* If the "remainder" comes out with the wrong sign, fix it. */
- if (f2 < 0 ? 0 < f1 : f1 < 0)
+ if (f2 < 0 ? f1 > 0 : f1 < 0)
f1 += f2;
return make_float (f1);
\f
DEFUN ("fceiling", Ffceiling, Sfceiling, 1, 1, 0,
doc: /* Return the smallest integer no less than ARG, as a float.
-\(Round toward +inf.\) */)
+\(Round toward +inf.) */)
(Lisp_Object arg)
{
double d = extract_float (arg);
DEFUN ("ffloor", Fffloor, Sffloor, 1, 1, 0,
doc: /* Return the largest integer no greater than ARG, as a float.
-\(Round towards -inf.\) */)
+\(Round towards -inf.) */)
(Lisp_Object arg)
{
double d = extract_float (arg);
defsubr (&Sexp);
defsubr (&Sexpt);
defsubr (&Slog);
- defsubr (&Slog10);
defsubr (&Ssqrt);
defsubr (&Sabs);