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