(rmail-get-new-mail): Fix return value to match doc.
[bpt/emacs.git] / src / floatfns.c
CommitLineData
b70021f4 1/* Primitive operations on floating point for GNU Emacs Lisp interpreter.
3a22ee35 2 Copyright (C) 1988, 1993, 1994 Free Software Foundation, Inc.
b70021f4
MR
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
4746118a 8the Free Software Foundation; either version 2, or (at your option)
b70021f4
MR
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
3b7ad313
EN
18the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA. */
b70021f4
MR
20
21
4b6baf5f
RS
22/* ANSI C requires only these float functions:
23 acos, asin, atan, atan2, ceil, cos, cosh, exp, fabs, floor, fmod,
24 frexp, ldexp, log, log10, modf, pow, sin, sinh, sqrt, tan, tanh.
25
26 Define HAVE_INVERSE_HYPERBOLIC if you have acosh, asinh, and atanh.
27 Define HAVE_CBRT if you have cbrt.
28 Define HAVE_RINT if you have rint.
29 If you don't define these, then the appropriate routines will be simulated.
30
31 Define HAVE_MATHERR if on a system supporting the SysV matherr callback.
32 (This should happen automatically.)
33
34 Define FLOAT_CHECK_ERRNO if the float library routines set errno.
35 This has no effect if HAVE_MATHERR is defined.
36
37 Define FLOAT_CATCH_SIGILL if the float library routines signal SIGILL.
38 (What systems actually do this? Please let us know.)
39
40 Define FLOAT_CHECK_DOMAIN if the float library doesn't handle errors by
8e6208c5 41 either setting errno, or signaling SIGFPE/SIGILL. Otherwise, domain and
4b6baf5f
RS
42 range checking will happen before calling the float routines. This has
43 no effect if HAVE_MATHERR is defined (since matherr will be called when
44 a domain error occurs.)
45 */
46
b70021f4
MR
47#include <signal.h>
48
18160b98 49#include <config.h>
b70021f4 50#include "lisp.h"
e065a56e 51#include "syssignal.h"
b70021f4 52
b70021f4 53#ifdef LISP_FLOAT_TYPE
265a9e55 54
d137ae2f
PE
55#if STDC_HEADERS
56#include <float.h>
57#endif
58
59/* If IEEE_FLOATING_POINT isn't defined, default it from FLT_*. */
60#ifndef IEEE_FLOATING_POINT
61#if (FLT_RADIX == 2 && FLT_MANT_DIG == 24 \
62 && FLT_MIN_EXP == -125 && FLT_MAX_EXP == 128)
63#define IEEE_FLOATING_POINT 1
64#else
65#define IEEE_FLOATING_POINT 0
66#endif
67#endif
68
4cd7a373
RS
69/* Work around a problem that happens because math.h on hpux 7
70 defines two static variables--which, in Emacs, are not really static,
71 because `static' is defined as nothing. The problem is that they are
72 defined both here and in lread.c.
73 These macros prevent the name conflict. */
74#if defined (HPUX) && !defined (HPUX8)
75#define _MAXLDBL floatfns_maxldbl
76#define _NMAXLDBL floatfns_nmaxldbl
77#endif
78
b70021f4 79#include <math.h>
4b6baf5f 80
32085e8e 81/* This declaration is omitted on some systems, like Ultrix. */
7a4720e2 82#if !defined (HPUX) && defined (HAVE_LOGB) && !defined (logb)
c26406fe 83extern double logb ();
7a4720e2 84#endif /* not HPUX and HAVE_LOGB and no logb macro */
c26406fe 85
4b6baf5f
RS
86#if defined(DOMAIN) && defined(SING) && defined(OVERFLOW)
87 /* If those are defined, then this is probably a `matherr' machine. */
88# ifndef HAVE_MATHERR
89# define HAVE_MATHERR
90# endif
91#endif
92
c0f0a4a2 93#ifdef NO_MATHERR
f89182a2
RS
94#undef HAVE_MATHERR
95#endif
96
4b6baf5f
RS
97#ifdef HAVE_MATHERR
98# ifdef FLOAT_CHECK_ERRNO
99# undef FLOAT_CHECK_ERRNO
100# endif
101# ifdef FLOAT_CHECK_DOMAIN
102# undef FLOAT_CHECK_DOMAIN
103# endif
104#endif
105
106#ifndef NO_FLOAT_CHECK_ERRNO
107#define FLOAT_CHECK_ERRNO
108#endif
109
110#ifdef FLOAT_CHECK_ERRNO
111# include <errno.h>
265a9e55
JB
112
113extern int errno;
4b6baf5f 114#endif
265a9e55
JB
115
116/* Avoid traps on VMS from sinh and cosh.
117 All the other functions set errno instead. */
118
119#ifdef VMS
120#undef cosh
121#undef sinh
122#define cosh(x) ((exp(x)+exp(-x))*0.5)
123#define sinh(x) ((exp(x)-exp(-x))*0.5)
124#endif /* VMS */
125
4b6baf5f
RS
126#ifndef HAVE_RINT
127#define rint(x) (floor((x)+0.5))
128#endif
129
4746118a 130static SIGTYPE float_error ();
b70021f4
MR
131
132/* Nonzero while executing in floating point.
133 This tells float_error what to do. */
134
135static int in_float;
136
137/* If an argument is out of range for a mathematical function,
21876236
RS
138 here is the actual argument value to use in the error message.
139 These variables are used only across the floating point library call
140 so there is no need to staticpro them. */
b70021f4 141
4b6baf5f
RS
142static Lisp_Object float_error_arg, float_error_arg2;
143
144static char *float_error_fn_name;
b70021f4 145
265a9e55
JB
146/* Evaluate the floating point expression D, recording NUM
147 as the original argument for error messages.
148 D is normally an assignment expression.
f8d83099
JB
149 Handle errors which may result in signals or may set errno.
150
151 Note that float_error may be declared to return void, so you can't
152 just cast the zero after the colon to (SIGTYPE) to make the types
153 check properly. */
265a9e55 154
4b6baf5f
RS
155#ifdef FLOAT_CHECK_ERRNO
156#define IN_FLOAT(d, name, num) \
157 do { \
158 float_error_arg = num; \
159 float_error_fn_name = name; \
160 in_float = 1; errno = 0; (d); in_float = 0; \
161 switch (errno) { \
162 case 0: break; \
163 case EDOM: domain_error (float_error_fn_name, float_error_arg); \
164 case ERANGE: range_error (float_error_fn_name, float_error_arg); \
165 default: arith_error (float_error_fn_name, float_error_arg); \
166 } \
167 } while (0)
168#define IN_FLOAT2(d, name, num, num2) \
169 do { \
170 float_error_arg = num; \
171 float_error_arg2 = num2; \
172 float_error_fn_name = name; \
173 in_float = 1; errno = 0; (d); in_float = 0; \
174 switch (errno) { \
175 case 0: break; \
176 case EDOM: domain_error (float_error_fn_name, float_error_arg); \
177 case ERANGE: range_error (float_error_fn_name, float_error_arg); \
178 default: arith_error (float_error_fn_name, float_error_arg); \
179 } \
180 } while (0)
181#else
f8131ed2 182#define IN_FLOAT(d, name, num) (in_float = 1, (d), in_float = 0)
4b6baf5f
RS
183#define IN_FLOAT2(d, name, num, num2) (in_float = 1, (d), in_float = 0)
184#endif
185
81a63ccc
KH
186/* Convert float to Lisp_Int if it fits, else signal a range error
187 using the given arguments. */
188#define FLOAT_TO_INT(x, i, name, num) \
189 do \
190 { \
7936dcdb
RS
191 if ((x) >= (((EMACS_INT) 1) << (VALBITS-1)) || \
192 (x) <= - (((EMACS_INT) 1) << (VALBITS-1)) - 1) \
81a63ccc 193 range_error (name, num); \
e0cb2a68 194 XSETINT (i, (EMACS_INT)(x)); \
81a63ccc
KH
195 } \
196 while (0)
197#define FLOAT_TO_INT2(x, i, name, num1, num2) \
198 do \
199 { \
7936dcdb
RS
200 if ((x) >= (((EMACS_INT) 1) << (VALBITS-1)) || \
201 (x) <= - (((EMACS_INT) 1) << (VALBITS-1)) - 1) \
81a63ccc 202 range_error2 (name, num1, num2); \
e0cb2a68 203 XSETINT (i, (EMACS_INT)(x)); \
81a63ccc
KH
204 } \
205 while (0)
206
4b6baf5f
RS
207#define arith_error(op,arg) \
208 Fsignal (Qarith_error, Fcons (build_string ((op)), Fcons ((arg), Qnil)))
209#define range_error(op,arg) \
210 Fsignal (Qrange_error, Fcons (build_string ((op)), Fcons ((arg), Qnil)))
81a63ccc
KH
211#define range_error2(op,a1,a2) \
212 Fsignal (Qrange_error, Fcons (build_string ((op)), \
213 Fcons ((a1), Fcons ((a2), Qnil))))
4b6baf5f
RS
214#define domain_error(op,arg) \
215 Fsignal (Qdomain_error, Fcons (build_string ((op)), Fcons ((arg), Qnil)))
216#define domain_error2(op,a1,a2) \
81a63ccc
KH
217 Fsignal (Qdomain_error, Fcons (build_string ((op)), \
218 Fcons ((a1), Fcons ((a2), Qnil))))
b70021f4
MR
219
220/* Extract a Lisp number as a `double', or signal an error. */
221
222double
223extract_float (num)
224 Lisp_Object num;
225{
226 CHECK_NUMBER_OR_FLOAT (num, 0);
227
207a45c1 228 if (FLOATP (num))
b70021f4
MR
229 return XFLOAT (num)->data;
230 return (double) XINT (num);
231}
c2d4ea74
RS
232\f
233/* Trig functions. */
b70021f4
MR
234
235DEFUN ("acos", Facos, Sacos, 1, 1, 0,
236 "Return the inverse cosine of ARG.")
4b6baf5f
RS
237 (arg)
238 register Lisp_Object arg;
b70021f4 239{
4b6baf5f
RS
240 double d = extract_float (arg);
241#ifdef FLOAT_CHECK_DOMAIN
242 if (d > 1.0 || d < -1.0)
243 domain_error ("acos", arg);
244#endif
245 IN_FLOAT (d = acos (d), "acos", arg);
b70021f4
MR
246 return make_float (d);
247}
248
c2d4ea74
RS
249DEFUN ("asin", Fasin, Sasin, 1, 1, 0,
250 "Return the inverse sine of ARG.")
4b6baf5f
RS
251 (arg)
252 register Lisp_Object arg;
b70021f4 253{
4b6baf5f
RS
254 double d = extract_float (arg);
255#ifdef FLOAT_CHECK_DOMAIN
256 if (d > 1.0 || d < -1.0)
257 domain_error ("asin", arg);
258#endif
259 IN_FLOAT (d = asin (d), "asin", arg);
b70021f4
MR
260 return make_float (d);
261}
262
c2d4ea74
RS
263DEFUN ("atan", Fatan, Satan, 1, 1, 0,
264 "Return the inverse tangent of ARG.")
4b6baf5f
RS
265 (arg)
266 register Lisp_Object arg;
b70021f4 267{
4b6baf5f
RS
268 double d = extract_float (arg);
269 IN_FLOAT (d = atan (d), "atan", arg);
b70021f4
MR
270 return make_float (d);
271}
272
c2d4ea74
RS
273DEFUN ("cos", Fcos, Scos, 1, 1, 0,
274 "Return the cosine of ARG.")
4b6baf5f
RS
275 (arg)
276 register Lisp_Object arg;
b70021f4 277{
4b6baf5f
RS
278 double d = extract_float (arg);
279 IN_FLOAT (d = cos (d), "cos", arg);
b70021f4
MR
280 return make_float (d);
281}
282
c2d4ea74
RS
283DEFUN ("sin", Fsin, Ssin, 1, 1, 0,
284 "Return the sine of ARG.")
4b6baf5f
RS
285 (arg)
286 register Lisp_Object arg;
b70021f4 287{
4b6baf5f
RS
288 double d = extract_float (arg);
289 IN_FLOAT (d = sin (d), "sin", arg);
b70021f4
MR
290 return make_float (d);
291}
292
c2d4ea74
RS
293DEFUN ("tan", Ftan, Stan, 1, 1, 0,
294 "Return the tangent of ARG.")
4b6baf5f
RS
295 (arg)
296 register Lisp_Object arg;
297{
298 double d = extract_float (arg);
299 double c = cos (d);
300#ifdef FLOAT_CHECK_DOMAIN
301 if (c == 0.0)
302 domain_error ("tan", arg);
303#endif
304 IN_FLOAT (d = sin (d) / c, "tan", arg);
b70021f4
MR
305 return make_float (d);
306}
307\f
c2d4ea74
RS
308#if 0 /* Leave these out unless we find there's a reason for them. */
309
b70021f4
MR
310DEFUN ("bessel-j0", Fbessel_j0, Sbessel_j0, 1, 1, 0,
311 "Return the bessel function j0 of ARG.")
4b6baf5f
RS
312 (arg)
313 register Lisp_Object arg;
b70021f4 314{
4b6baf5f
RS
315 double d = extract_float (arg);
316 IN_FLOAT (d = j0 (d), "bessel-j0", arg);
b70021f4
MR
317 return make_float (d);
318}
319
320DEFUN ("bessel-j1", Fbessel_j1, Sbessel_j1, 1, 1, 0,
321 "Return the bessel function j1 of ARG.")
4b6baf5f
RS
322 (arg)
323 register Lisp_Object arg;
b70021f4 324{
4b6baf5f
RS
325 double d = extract_float (arg);
326 IN_FLOAT (d = j1 (d), "bessel-j1", arg);
b70021f4
MR
327 return make_float (d);
328}
329
330DEFUN ("bessel-jn", Fbessel_jn, Sbessel_jn, 2, 2, 0,
331 "Return the order N bessel function output jn of ARG.\n\
332The first arg (the order) is truncated to an integer.")
3e670702
EN
333 (n, arg)
334 register Lisp_Object n, arg;
b70021f4 335{
3e670702
EN
336 int i1 = extract_float (n);
337 double f2 = extract_float (arg);
b70021f4 338
3e670702 339 IN_FLOAT (f2 = jn (i1, f2), "bessel-jn", n);
b70021f4
MR
340 return make_float (f2);
341}
342
343DEFUN ("bessel-y0", Fbessel_y0, Sbessel_y0, 1, 1, 0,
344 "Return the bessel function y0 of ARG.")
4b6baf5f
RS
345 (arg)
346 register Lisp_Object arg;
b70021f4 347{
4b6baf5f
RS
348 double d = extract_float (arg);
349 IN_FLOAT (d = y0 (d), "bessel-y0", arg);
b70021f4
MR
350 return make_float (d);
351}
352
353DEFUN ("bessel-y1", Fbessel_y1, Sbessel_y1, 1, 1, 0,
354 "Return the bessel function y1 of ARG.")
4b6baf5f
RS
355 (arg)
356 register Lisp_Object arg;
b70021f4 357{
4b6baf5f
RS
358 double d = extract_float (arg);
359 IN_FLOAT (d = y1 (d), "bessel-y0", arg);
b70021f4
MR
360 return make_float (d);
361}
362
363DEFUN ("bessel-yn", Fbessel_yn, Sbessel_yn, 2, 2, 0,
364 "Return the order N bessel function output yn of ARG.\n\
365The first arg (the order) is truncated to an integer.")
3e670702
EN
366 (n, arg)
367 register Lisp_Object n, arg;
b70021f4 368{
3e670702
EN
369 int i1 = extract_float (n);
370 double f2 = extract_float (arg);
b70021f4 371
3e670702 372 IN_FLOAT (f2 = yn (i1, f2), "bessel-yn", n);
b70021f4
MR
373 return make_float (f2);
374}
b70021f4 375
c2d4ea74
RS
376#endif
377\f
378#if 0 /* Leave these out unless we see they are worth having. */
b70021f4
MR
379
380DEFUN ("erf", Ferf, Serf, 1, 1, 0,
381 "Return the mathematical error function of ARG.")
4b6baf5f
RS
382 (arg)
383 register Lisp_Object arg;
b70021f4 384{
4b6baf5f
RS
385 double d = extract_float (arg);
386 IN_FLOAT (d = erf (d), "erf", arg);
b70021f4
MR
387 return make_float (d);
388}
389
390DEFUN ("erfc", Ferfc, Serfc, 1, 1, 0,
391 "Return the complementary error function of ARG.")
4b6baf5f
RS
392 (arg)
393 register Lisp_Object arg;
b70021f4 394{
4b6baf5f
RS
395 double d = extract_float (arg);
396 IN_FLOAT (d = erfc (d), "erfc", arg);
b70021f4
MR
397 return make_float (d);
398}
399
b70021f4
MR
400DEFUN ("log-gamma", Flog_gamma, Slog_gamma, 1, 1, 0,
401 "Return the log gamma of ARG.")
4b6baf5f
RS
402 (arg)
403 register Lisp_Object arg;
b70021f4 404{
4b6baf5f
RS
405 double d = extract_float (arg);
406 IN_FLOAT (d = lgamma (d), "log-gamma", arg);
b70021f4
MR
407 return make_float (d);
408}
409
4b6baf5f 410DEFUN ("cube-root", Fcube_root, Scube_root, 1, 1, 0,
c2d4ea74 411 "Return the cube root of ARG.")
4b6baf5f
RS
412 (arg)
413 register Lisp_Object arg;
b70021f4 414{
4b6baf5f
RS
415 double d = extract_float (arg);
416#ifdef HAVE_CBRT
417 IN_FLOAT (d = cbrt (d), "cube-root", arg);
418#else
419 if (d >= 0.0)
420 IN_FLOAT (d = pow (d, 1.0/3.0), "cube-root", arg);
421 else
422 IN_FLOAT (d = -pow (-d, 1.0/3.0), "cube-root", arg);
423#endif
b70021f4
MR
424 return make_float (d);
425}
426
706ac90d
RS
427#endif
428\f
c2d4ea74
RS
429DEFUN ("exp", Fexp, Sexp, 1, 1, 0,
430 "Return the exponential base e of ARG.")
4b6baf5f
RS
431 (arg)
432 register Lisp_Object arg;
433{
434 double d = extract_float (arg);
435#ifdef FLOAT_CHECK_DOMAIN
436 if (d > 709.7827) /* Assume IEEE doubles here */
437 range_error ("exp", arg);
438 else if (d < -709.0)
439 return make_float (0.0);
440 else
441#endif
442 IN_FLOAT (d = exp (d), "exp", arg);
b70021f4
MR
443 return make_float (d);
444}
445
b70021f4 446DEFUN ("expt", Fexpt, Sexpt, 2, 2, 0,
4fd72a6a 447 "Return the exponential ARG1 ** ARG2.")
4b6baf5f
RS
448 (arg1, arg2)
449 register Lisp_Object arg1, arg2;
b70021f4
MR
450{
451 double f1, f2;
452
4b6baf5f
RS
453 CHECK_NUMBER_OR_FLOAT (arg1, 0);
454 CHECK_NUMBER_OR_FLOAT (arg2, 0);
207a45c1
KH
455 if (INTEGERP (arg1) /* common lisp spec */
456 && INTEGERP (arg2)) /* don't promote, if both are ints */
b70021f4 457 { /* this can be improved by pre-calculating */
9a51b24a 458 EMACS_INT acc, x, y; /* some binary powers of x then accumulating */
4be1d460
RS
459 Lisp_Object val;
460
4b6baf5f
RS
461 x = XINT (arg1);
462 y = XINT (arg2);
b70021f4
MR
463 acc = 1;
464
465 if (y < 0)
466 {
4b6baf5f
RS
467 if (x == 1)
468 acc = 1;
469 else if (x == -1)
470 acc = (y & 1) ? -1 : 1;
471 else
472 acc = 0;
b70021f4
MR
473 }
474 else
475 {
4b6baf5f
RS
476 while (y > 0)
477 {
478 if (y & 1)
479 acc *= x;
480 x *= x;
481 y = (unsigned)y >> 1;
482 }
b70021f4 483 }
e0cb2a68 484 XSETINT (val, acc);
4be1d460 485 return val;
b70021f4 486 }
207a45c1
KH
487 f1 = FLOATP (arg1) ? XFLOAT (arg1)->data : XINT (arg1);
488 f2 = FLOATP (arg2) ? XFLOAT (arg2)->data : XINT (arg2);
4b6baf5f
RS
489 /* Really should check for overflow, too */
490 if (f1 == 0.0 && f2 == 0.0)
491 f1 = 1.0;
492#ifdef FLOAT_CHECK_DOMAIN
493 else if ((f1 == 0.0 && f2 < 0.0) || (f1 < 0 && f2 != floor(f2)))
494 domain_error2 ("expt", arg1, arg2);
495#endif
28d849db 496 IN_FLOAT2 (f1 = pow (f1, f2), "expt", arg1, arg2);
b70021f4
MR
497 return make_float (f1);
498}
c2d4ea74 499
56abb480 500DEFUN ("log", Flog, Slog, 1, 2, 0,
4b6baf5f
RS
501 "Return the natural logarithm of ARG.\n\
502If second optional argument BASE is given, return log ARG using that base.")
503 (arg, base)
504 register Lisp_Object arg, base;
b70021f4 505{
4b6baf5f 506 double d = extract_float (arg);
56abb480 507
4b6baf5f
RS
508#ifdef FLOAT_CHECK_DOMAIN
509 if (d <= 0.0)
510 domain_error2 ("log", arg, base);
511#endif
56abb480 512 if (NILP (base))
4b6baf5f 513 IN_FLOAT (d = log (d), "log", arg);
56abb480
JB
514 else
515 {
516 double b = extract_float (base);
517
4b6baf5f
RS
518#ifdef FLOAT_CHECK_DOMAIN
519 if (b <= 0.0 || b == 1.0)
520 domain_error2 ("log", arg, base);
521#endif
522 if (b == 10.0)
523 IN_FLOAT2 (d = log10 (d), "log", arg, base);
524 else
f8131ed2 525 IN_FLOAT2 (d = log (d) / log (b), "log", arg, base);
56abb480 526 }
b70021f4
MR
527 return make_float (d);
528}
529
c2d4ea74
RS
530DEFUN ("log10", Flog10, Slog10, 1, 1, 0,
531 "Return the logarithm base 10 of ARG.")
4b6baf5f
RS
532 (arg)
533 register Lisp_Object arg;
b70021f4 534{
4b6baf5f
RS
535 double d = extract_float (arg);
536#ifdef FLOAT_CHECK_DOMAIN
537 if (d <= 0.0)
538 domain_error ("log10", arg);
539#endif
540 IN_FLOAT (d = log10 (d), "log10", arg);
c2d4ea74
RS
541 return make_float (d);
542}
543
b70021f4
MR
544DEFUN ("sqrt", Fsqrt, Ssqrt, 1, 1, 0,
545 "Return the square root of ARG.")
4b6baf5f
RS
546 (arg)
547 register Lisp_Object arg;
b70021f4 548{
4b6baf5f
RS
549 double d = extract_float (arg);
550#ifdef FLOAT_CHECK_DOMAIN
551 if (d < 0.0)
552 domain_error ("sqrt", arg);
553#endif
554 IN_FLOAT (d = sqrt (d), "sqrt", arg);
b70021f4
MR
555 return make_float (d);
556}
c2d4ea74 557\f
706ac90d 558#if 0 /* Not clearly worth adding. */
b70021f4 559
c2d4ea74
RS
560DEFUN ("acosh", Facosh, Sacosh, 1, 1, 0,
561 "Return the inverse hyperbolic cosine of ARG.")
4b6baf5f
RS
562 (arg)
563 register Lisp_Object arg;
b70021f4 564{
4b6baf5f
RS
565 double d = extract_float (arg);
566#ifdef FLOAT_CHECK_DOMAIN
567 if (d < 1.0)
568 domain_error ("acosh", arg);
569#endif
570#ifdef HAVE_INVERSE_HYPERBOLIC
571 IN_FLOAT (d = acosh (d), "acosh", arg);
572#else
573 IN_FLOAT (d = log (d + sqrt (d*d - 1.0)), "acosh", arg);
574#endif
c2d4ea74
RS
575 return make_float (d);
576}
577
578DEFUN ("asinh", Fasinh, Sasinh, 1, 1, 0,
579 "Return the inverse hyperbolic sine of ARG.")
4b6baf5f
RS
580 (arg)
581 register Lisp_Object arg;
c2d4ea74 582{
4b6baf5f
RS
583 double d = extract_float (arg);
584#ifdef HAVE_INVERSE_HYPERBOLIC
585 IN_FLOAT (d = asinh (d), "asinh", arg);
586#else
587 IN_FLOAT (d = log (d + sqrt (d*d + 1.0)), "asinh", arg);
588#endif
c2d4ea74
RS
589 return make_float (d);
590}
591
592DEFUN ("atanh", Fatanh, Satanh, 1, 1, 0,
593 "Return the inverse hyperbolic tangent of ARG.")
4b6baf5f
RS
594 (arg)
595 register Lisp_Object arg;
c2d4ea74 596{
4b6baf5f
RS
597 double d = extract_float (arg);
598#ifdef FLOAT_CHECK_DOMAIN
599 if (d >= 1.0 || d <= -1.0)
600 domain_error ("atanh", arg);
601#endif
602#ifdef HAVE_INVERSE_HYPERBOLIC
603 IN_FLOAT (d = atanh (d), "atanh", arg);
604#else
605 IN_FLOAT (d = 0.5 * log ((1.0 + d) / (1.0 - d)), "atanh", arg);
606#endif
c2d4ea74
RS
607 return make_float (d);
608}
609
610DEFUN ("cosh", Fcosh, Scosh, 1, 1, 0,
611 "Return the hyperbolic cosine of ARG.")
4b6baf5f
RS
612 (arg)
613 register Lisp_Object arg;
c2d4ea74 614{
4b6baf5f
RS
615 double d = extract_float (arg);
616#ifdef FLOAT_CHECK_DOMAIN
617 if (d > 710.0 || d < -710.0)
618 range_error ("cosh", arg);
619#endif
620 IN_FLOAT (d = cosh (d), "cosh", arg);
c2d4ea74
RS
621 return make_float (d);
622}
623
624DEFUN ("sinh", Fsinh, Ssinh, 1, 1, 0,
625 "Return the hyperbolic sine of ARG.")
4b6baf5f
RS
626 (arg)
627 register Lisp_Object arg;
c2d4ea74 628{
4b6baf5f
RS
629 double d = extract_float (arg);
630#ifdef FLOAT_CHECK_DOMAIN
631 if (d > 710.0 || d < -710.0)
632 range_error ("sinh", arg);
633#endif
634 IN_FLOAT (d = sinh (d), "sinh", arg);
b70021f4
MR
635 return make_float (d);
636}
637
638DEFUN ("tanh", Ftanh, Stanh, 1, 1, 0,
639 "Return the hyperbolic tangent of ARG.")
4b6baf5f
RS
640 (arg)
641 register Lisp_Object arg;
b70021f4 642{
4b6baf5f
RS
643 double d = extract_float (arg);
644 IN_FLOAT (d = tanh (d), "tanh", arg);
b70021f4
MR
645 return make_float (d);
646}
c2d4ea74 647#endif
b70021f4
MR
648\f
649DEFUN ("abs", Fabs, Sabs, 1, 1, 0,
650 "Return the absolute value of ARG.")
4b6baf5f
RS
651 (arg)
652 register Lisp_Object arg;
b70021f4 653{
4b6baf5f 654 CHECK_NUMBER_OR_FLOAT (arg, 0);
b70021f4 655
207a45c1 656 if (FLOATP (arg))
4b6baf5f
RS
657 IN_FLOAT (arg = make_float (fabs (XFLOAT (arg)->data)), "abs", arg);
658 else if (XINT (arg) < 0)
db37cb37 659 XSETINT (arg, - XINT (arg));
b70021f4 660
4b6baf5f 661 return arg;
b70021f4
MR
662}
663
664DEFUN ("float", Ffloat, Sfloat, 1, 1, 0,
665 "Return the floating point number equal to ARG.")
4b6baf5f
RS
666 (arg)
667 register Lisp_Object arg;
b70021f4 668{
4b6baf5f 669 CHECK_NUMBER_OR_FLOAT (arg, 0);
b70021f4 670
207a45c1 671 if (INTEGERP (arg))
4b6baf5f 672 return make_float ((double) XINT (arg));
b70021f4 673 else /* give 'em the same float back */
4b6baf5f 674 return arg;
b70021f4
MR
675}
676
677DEFUN ("logb", Flogb, Slogb, 1, 1, 0,
1a3ac8b9 678 "Returns largest integer <= the base 2 log of the magnitude of ARG.\n\
b70021f4 679This is the same as the exponent of a float.")
4b6baf5f
RS
680 (arg)
681 Lisp_Object arg;
b70021f4 682{
340176df 683 Lisp_Object val;
a7bf3c54 684 EMACS_INT value;
5bf54166 685 double f = extract_float (arg);
340176df 686
6694b327
KH
687 if (f == 0.0)
688 value = -(VALMASK >> 1);
689 else
690 {
6d3c6adb 691#ifdef HAVE_LOGB
6694b327 692 IN_FLOAT (value = logb (f), "logb", arg);
6d3c6adb
JB
693#else
694#ifdef HAVE_FREXP
c8bf6cf3
KH
695 int ivalue;
696 IN_FLOAT (frexp (f, &ivalue), "logb", arg);
697 value = ivalue - 1;
c26406fe 698#else
6694b327
KH
699 int i;
700 double d;
701 if (f < 0.0)
702 f = -f;
703 value = -1;
704 while (f < 0.5)
705 {
706 for (i = 1, d = 0.5; d * d >= f; i += i)
707 d *= d;
708 f /= d;
709 value -= i;
710 }
711 while (f >= 1.0)
712 {
713 for (i = 1, d = 2.0; d * d <= f; i += i)
714 d *= d;
715 f /= d;
716 value += i;
717 }
6d3c6adb 718#endif
340176df 719#endif
6694b327 720 }
e0cb2a68 721 XSETINT (val, value);
c26406fe 722 return val;
b70021f4
MR
723}
724
fc2157cb
PE
725#endif /* LISP_FLOAT_TYPE */
726
727
acbbacbe
PE
728/* the rounding functions */
729
730static Lisp_Object
731rounding_driver (arg, divisor, double_round, int_round2, name)
fc2157cb 732 register Lisp_Object arg, divisor;
acbbacbe
PE
733 double (*double_round) ();
734 EMACS_INT (*int_round2) ();
735 char *name;
b70021f4 736{
4b6baf5f 737 CHECK_NUMBER_OR_FLOAT (arg, 0);
b70021f4 738
fc2157cb
PE
739 if (! NILP (divisor))
740 {
9a51b24a 741 EMACS_INT i1, i2;
fc2157cb
PE
742
743 CHECK_NUMBER_OR_FLOAT (divisor, 1);
744
745#ifdef LISP_FLOAT_TYPE
207a45c1 746 if (FLOATP (arg) || FLOATP (divisor))
fc2157cb
PE
747 {
748 double f1, f2;
749
207a45c1
KH
750 f1 = FLOATP (arg) ? XFLOAT (arg)->data : XINT (arg);
751 f2 = (FLOATP (divisor) ? XFLOAT (divisor)->data : XINT (divisor));
d137ae2f 752 if (! IEEE_FLOATING_POINT && f2 == 0)
fc2157cb
PE
753 Fsignal (Qarith_error, Qnil);
754
acbbacbe
PE
755 IN_FLOAT2 (f1 = (*double_round) (f1 / f2), name, arg, divisor);
756 FLOAT_TO_INT2 (f1, arg, name, arg, divisor);
fc2157cb
PE
757 return arg;
758 }
759#endif
760
761 i1 = XINT (arg);
762 i2 = XINT (divisor);
763
764 if (i2 == 0)
765 Fsignal (Qarith_error, Qnil);
766
acbbacbe 767 XSETINT (arg, (*int_round2) (i1, i2));
fc2157cb
PE
768 return arg;
769 }
770
771#ifdef LISP_FLOAT_TYPE
207a45c1 772 if (FLOATP (arg))
81a63ccc
KH
773 {
774 double d;
acbbacbe
PE
775
776 IN_FLOAT (d = (*double_round) (XFLOAT (arg)->data), name, arg);
777 FLOAT_TO_INT (d, arg, name, arg);
81a63ccc 778 }
fc2157cb 779#endif
b70021f4 780
4b6baf5f 781 return arg;
b70021f4
MR
782}
783
acbbacbe
PE
784/* With C's /, the result is implementation-defined if either operand
785 is negative, so take care with negative operands in the following
786 integer functions. */
787
788static EMACS_INT
789ceiling2 (i1, i2)
790 EMACS_INT i1, i2;
791{
792 return (i2 < 0
793 ? (i1 < 0 ? ((-1 - i1) / -i2) + 1 : - (i1 / -i2))
794 : (i1 <= 0 ? - (-i1 / i2) : ((i1 - 1) / i2) + 1));
795}
796
797static EMACS_INT
798floor2 (i1, i2)
799 EMACS_INT i1, i2;
800{
801 return (i2 < 0
802 ? (i1 <= 0 ? -i1 / -i2 : -1 - ((i1 - 1) / -i2))
803 : (i1 < 0 ? -1 - ((-1 - i1) / i2) : i1 / i2));
804}
805
806static EMACS_INT
807truncate2 (i1, i2)
808 EMACS_INT i1, i2;
809{
810 return (i2 < 0
811 ? (i1 < 0 ? -i1 / -i2 : - (i1 / -i2))
812 : (i1 < 0 ? - (-i1 / i2) : i1 / i2));
813}
814
815static EMACS_INT
816round2 (i1, i2)
817 EMACS_INT i1, i2;
818{
819 /* The C language's division operator gives us one remainder R, but
820 we want the remainder R1 on the other side of 0 if R1 is closer
821 to 0 than R is; because we want to round to even, we also want R1
822 if R and R1 are the same distance from 0 and if C's quotient is
823 odd. */
824 EMACS_INT q = i1 / i2;
825 EMACS_INT r = i1 % i2;
826 EMACS_INT abs_r = r < 0 ? -r : r;
827 EMACS_INT abs_r1 = (i2 < 0 ? -i2 : i2) - abs_r;
828 return q + (abs_r + (q & 1) <= abs_r1 ? 0 : (i2 ^ r) < 0 ? -1 : 1);
829}
830
831static double
832double_identity (d)
833 double d;
834{
835 return d;
836}
837
838DEFUN ("ceiling", Fceiling, Sceiling, 1, 2, 0,
839 "Return the smallest integer no less than ARG. (Round toward +inf.)\n\
840With optional DIVISOR, return the smallest integer no less than ARG/DIVISOR.")
841 (arg, divisor)
842 Lisp_Object arg, divisor;
843{
844 return rounding_driver (arg, divisor, ceil, ceiling2, "ceiling");
845}
846
847DEFUN ("floor", Ffloor, Sfloor, 1, 2, 0,
848 "Return the largest integer no greater than ARG. (Round towards -inf.)\n\
849With optional DIVISOR, return the largest integer no greater than ARG/DIVISOR.")
850 (arg, divisor)
851 Lisp_Object arg, divisor;
852{
853 return rounding_driver (arg, divisor, floor, floor2, "floor");
854}
855
856DEFUN ("round", Fround, Sround, 1, 2, 0,
857 "Return the nearest integer to ARG.\n\
858With optional DIVISOR, return the nearest integer to ARG/DIVISOR.")
859 (arg, divisor)
860 Lisp_Object arg, divisor;
861{
862 return rounding_driver (arg, divisor, rint, round2, "round");
863}
864
865DEFUN ("truncate", Ftruncate, Struncate, 1, 2, 0,
866 "Truncate a floating point number to an int.\n\
867Rounds ARG toward zero.\n\
868With optional DIVISOR, truncate ARG/DIVISOR.")
869 (arg, divisor)
870 Lisp_Object arg, divisor;
871{
872 return rounding_driver (arg, divisor, double_identity, truncate2,
873 "truncate");
874}
875
fc2157cb
PE
876#ifdef LISP_FLOAT_TYPE
877
d137ae2f
PE
878Lisp_Object
879fmod_float (x, y)
880 register Lisp_Object x, y;
881{
882 double f1, f2;
883
884 f1 = FLOATP (x) ? XFLOAT (x)->data : XINT (x);
885 f2 = FLOATP (y) ? XFLOAT (y)->data : XINT (y);
886
887 if (! IEEE_FLOATING_POINT && f2 == 0)
888 Fsignal (Qarith_error, Qnil);
889
890 /* If the "remainder" comes out with the wrong sign, fix it. */
891 IN_FLOAT2 ((f1 = fmod (f1, f2),
892 f1 = (f2 < 0 ? f1 > 0 : f1 < 0) ? f1 + f2 : f1),
893 "mod", x, y);
894 return make_float (f1);
895}
4b6baf5f 896\f
4b6baf5f
RS
897/* It's not clear these are worth adding. */
898
899DEFUN ("fceiling", Ffceiling, Sfceiling, 1, 1, 0,
900 "Return the smallest integer no less than ARG, as a float.\n\
901\(Round toward +inf.\)")
902 (arg)
903 register Lisp_Object arg;
904{
905 double d = extract_float (arg);
906 IN_FLOAT (d = ceil (d), "fceiling", arg);
907 return make_float (d);
908}
909
910DEFUN ("ffloor", Fffloor, Sffloor, 1, 1, 0,
911 "Return the largest integer no greater than ARG, as a float.\n\
912\(Round towards -inf.\)")
913 (arg)
914 register Lisp_Object arg;
915{
916 double d = extract_float (arg);
917 IN_FLOAT (d = floor (d), "ffloor", arg);
918 return make_float (d);
919}
b70021f4 920
4b6baf5f
RS
921DEFUN ("fround", Ffround, Sfround, 1, 1, 0,
922 "Return the nearest integer to ARG, as a float.")
923 (arg)
924 register Lisp_Object arg;
925{
926 double d = extract_float (arg);
892ed7e0 927 IN_FLOAT (d = rint (d), "fround", arg);
4b6baf5f
RS
928 return make_float (d);
929}
930
931DEFUN ("ftruncate", Fftruncate, Sftruncate, 1, 1, 0,
932 "Truncate a floating point number to an integral float value.\n\
933Rounds the value toward zero.")
934 (arg)
935 register Lisp_Object arg;
936{
937 double d = extract_float (arg);
938 if (d >= 0.0)
939 IN_FLOAT (d = floor (d), "ftruncate", arg);
940 else
a3fc5236 941 IN_FLOAT (d = ceil (d), "ftruncate", arg);
4b6baf5f 942 return make_float (d);
b70021f4
MR
943}
944\f
4b6baf5f 945#ifdef FLOAT_CATCH_SIGILL
4746118a 946static SIGTYPE
b70021f4
MR
947float_error (signo)
948 int signo;
949{
950 if (! in_float)
951 fatal_error_signal (signo);
952
6df54671 953#ifdef BSD_SYSTEM
b70021f4
MR
954#ifdef BSD4_1
955 sigrelse (SIGILL);
956#else /* not BSD4_1 */
e065a56e 957 sigsetmask (SIGEMPTYMASK);
b70021f4 958#endif /* not BSD4_1 */
265a9e55
JB
959#else
960 /* Must reestablish handler each time it is called. */
961 signal (SIGILL, float_error);
6df54671 962#endif /* BSD_SYSTEM */
b70021f4
MR
963
964 in_float = 0;
965
966 Fsignal (Qarith_error, Fcons (float_error_arg, Qnil));
967}
968
4b6baf5f
RS
969/* Another idea was to replace the library function `infnan'
970 where SIGILL is signaled. */
971
972#endif /* FLOAT_CATCH_SIGILL */
973
974#ifdef HAVE_MATHERR
975int
976matherr (x)
977 struct exception *x;
978{
979 Lisp_Object args;
980 if (! in_float)
981 /* Not called from emacs-lisp float routines; do the default thing. */
982 return 0;
983 if (!strcmp (x->name, "pow"))
984 x->name = "expt";
985
986 args
987 = Fcons (build_string (x->name),
988 Fcons (make_float (x->arg1),
989 ((!strcmp (x->name, "log") || !strcmp (x->name, "pow"))
990 ? Fcons (make_float (x->arg2), Qnil)
991 : Qnil)));
992 switch (x->type)
993 {
994 case DOMAIN: Fsignal (Qdomain_error, args); break;
995 case SING: Fsignal (Qsingularity_error, args); break;
996 case OVERFLOW: Fsignal (Qoverflow_error, args); break;
997 case UNDERFLOW: Fsignal (Qunderflow_error, args); break;
998 default: Fsignal (Qarith_error, args); break;
999 }
1000 return (1); /* don't set errno or print a message */
1001}
1002#endif /* HAVE_MATHERR */
1003
b70021f4
MR
1004init_floatfns ()
1005{
4b6baf5f 1006#ifdef FLOAT_CATCH_SIGILL
b70021f4 1007 signal (SIGILL, float_error);
4b6baf5f 1008#endif
b70021f4
MR
1009 in_float = 0;
1010}
1011
fc2157cb
PE
1012#else /* not LISP_FLOAT_TYPE */
1013
1014init_floatfns ()
1015{}
1016
1017#endif /* not LISP_FLOAT_TYPE */
1018
b70021f4
MR
1019syms_of_floatfns ()
1020{
fc2157cb 1021#ifdef LISP_FLOAT_TYPE
b70021f4 1022 defsubr (&Sacos);
b70021f4 1023 defsubr (&Sasin);
b70021f4 1024 defsubr (&Satan);
c2d4ea74
RS
1025 defsubr (&Scos);
1026 defsubr (&Ssin);
1027 defsubr (&Stan);
1028#if 0
1029 defsubr (&Sacosh);
1030 defsubr (&Sasinh);
b70021f4 1031 defsubr (&Satanh);
c2d4ea74
RS
1032 defsubr (&Scosh);
1033 defsubr (&Ssinh);
1034 defsubr (&Stanh);
b70021f4
MR
1035 defsubr (&Sbessel_y0);
1036 defsubr (&Sbessel_y1);
1037 defsubr (&Sbessel_yn);
1038 defsubr (&Sbessel_j0);
1039 defsubr (&Sbessel_j1);
1040 defsubr (&Sbessel_jn);
b70021f4
MR
1041 defsubr (&Serf);
1042 defsubr (&Serfc);
c2d4ea74 1043 defsubr (&Slog_gamma);
4b6baf5f 1044 defsubr (&Scube_root);
892ed7e0 1045#endif
4b6baf5f
RS
1046 defsubr (&Sfceiling);
1047 defsubr (&Sffloor);
1048 defsubr (&Sfround);
1049 defsubr (&Sftruncate);
b70021f4 1050 defsubr (&Sexp);
c2d4ea74 1051 defsubr (&Sexpt);
b70021f4
MR
1052 defsubr (&Slog);
1053 defsubr (&Slog10);
b70021f4 1054 defsubr (&Ssqrt);
b70021f4
MR
1055
1056 defsubr (&Sabs);
1057 defsubr (&Sfloat);
1058 defsubr (&Slogb);
acbbacbe 1059#endif /* LISP_FLOAT_TYPE */
b70021f4 1060 defsubr (&Sceiling);
acbbacbe 1061 defsubr (&Sfloor);
b70021f4
MR
1062 defsubr (&Sround);
1063 defsubr (&Struncate);
1064}