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