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