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