(Frem) [MSDOS]: use `fmod', not `drem'. Put in config.h?
[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 {
448 for (; y > 0; y--)
4b6baf5f
RS
449 while (y > 0)
450 {
451 if (y & 1)
452 acc *= x;
453 x *= x;
454 y = (unsigned)y >> 1;
455 }
b70021f4 456 }
4be1d460
RS
457 XSET (val, Lisp_Int, acc);
458 return val;
b70021f4 459 }
4b6baf5f
RS
460 f1 = (XTYPE (arg1) == Lisp_Float) ? XFLOAT (arg1)->data : XINT (arg1);
461 f2 = (XTYPE (arg2) == Lisp_Float) ? XFLOAT (arg2)->data : XINT (arg2);
462 /* Really should check for overflow, too */
463 if (f1 == 0.0 && f2 == 0.0)
464 f1 = 1.0;
465#ifdef FLOAT_CHECK_DOMAIN
466 else if ((f1 == 0.0 && f2 < 0.0) || (f1 < 0 && f2 != floor(f2)))
467 domain_error2 ("expt", arg1, arg2);
468#endif
28d849db 469 IN_FLOAT2 (f1 = pow (f1, f2), "expt", arg1, arg2);
b70021f4
MR
470 return make_float (f1);
471}
c2d4ea74 472
56abb480 473DEFUN ("log", Flog, Slog, 1, 2, 0,
4b6baf5f
RS
474 "Return the natural logarithm of ARG.\n\
475If second optional argument BASE is given, return log ARG using that base.")
476 (arg, base)
477 register Lisp_Object arg, base;
b70021f4 478{
4b6baf5f 479 double d = extract_float (arg);
56abb480 480
4b6baf5f
RS
481#ifdef FLOAT_CHECK_DOMAIN
482 if (d <= 0.0)
483 domain_error2 ("log", arg, base);
484#endif
56abb480 485 if (NILP (base))
4b6baf5f 486 IN_FLOAT (d = log (d), "log", arg);
56abb480
JB
487 else
488 {
489 double b = extract_float (base);
490
4b6baf5f
RS
491#ifdef FLOAT_CHECK_DOMAIN
492 if (b <= 0.0 || b == 1.0)
493 domain_error2 ("log", arg, base);
494#endif
495 if (b == 10.0)
496 IN_FLOAT2 (d = log10 (d), "log", arg, base);
497 else
f8131ed2 498 IN_FLOAT2 (d = log (d) / log (b), "log", arg, base);
56abb480 499 }
b70021f4
MR
500 return make_float (d);
501}
502
c2d4ea74
RS
503DEFUN ("log10", Flog10, Slog10, 1, 1, 0,
504 "Return the logarithm base 10 of ARG.")
4b6baf5f
RS
505 (arg)
506 register Lisp_Object arg;
b70021f4 507{
4b6baf5f
RS
508 double d = extract_float (arg);
509#ifdef FLOAT_CHECK_DOMAIN
510 if (d <= 0.0)
511 domain_error ("log10", arg);
512#endif
513 IN_FLOAT (d = log10 (d), "log10", arg);
c2d4ea74
RS
514 return make_float (d);
515}
516
b70021f4
MR
517DEFUN ("sqrt", Fsqrt, Ssqrt, 1, 1, 0,
518 "Return the square root of ARG.")
4b6baf5f
RS
519 (arg)
520 register Lisp_Object arg;
b70021f4 521{
4b6baf5f
RS
522 double d = extract_float (arg);
523#ifdef FLOAT_CHECK_DOMAIN
524 if (d < 0.0)
525 domain_error ("sqrt", arg);
526#endif
527 IN_FLOAT (d = sqrt (d), "sqrt", arg);
b70021f4
MR
528 return make_float (d);
529}
c2d4ea74 530\f
706ac90d 531#if 0 /* Not clearly worth adding. */
b70021f4 532
c2d4ea74
RS
533DEFUN ("acosh", Facosh, Sacosh, 1, 1, 0,
534 "Return the inverse hyperbolic cosine of ARG.")
4b6baf5f
RS
535 (arg)
536 register Lisp_Object arg;
b70021f4 537{
4b6baf5f
RS
538 double d = extract_float (arg);
539#ifdef FLOAT_CHECK_DOMAIN
540 if (d < 1.0)
541 domain_error ("acosh", arg);
542#endif
543#ifdef HAVE_INVERSE_HYPERBOLIC
544 IN_FLOAT (d = acosh (d), "acosh", arg);
545#else
546 IN_FLOAT (d = log (d + sqrt (d*d - 1.0)), "acosh", arg);
547#endif
c2d4ea74
RS
548 return make_float (d);
549}
550
551DEFUN ("asinh", Fasinh, Sasinh, 1, 1, 0,
552 "Return the inverse hyperbolic sine of ARG.")
4b6baf5f
RS
553 (arg)
554 register Lisp_Object arg;
c2d4ea74 555{
4b6baf5f
RS
556 double d = extract_float (arg);
557#ifdef HAVE_INVERSE_HYPERBOLIC
558 IN_FLOAT (d = asinh (d), "asinh", arg);
559#else
560 IN_FLOAT (d = log (d + sqrt (d*d + 1.0)), "asinh", arg);
561#endif
c2d4ea74
RS
562 return make_float (d);
563}
564
565DEFUN ("atanh", Fatanh, Satanh, 1, 1, 0,
566 "Return the inverse hyperbolic tangent of ARG.")
4b6baf5f
RS
567 (arg)
568 register Lisp_Object arg;
c2d4ea74 569{
4b6baf5f
RS
570 double d = extract_float (arg);
571#ifdef FLOAT_CHECK_DOMAIN
572 if (d >= 1.0 || d <= -1.0)
573 domain_error ("atanh", arg);
574#endif
575#ifdef HAVE_INVERSE_HYPERBOLIC
576 IN_FLOAT (d = atanh (d), "atanh", arg);
577#else
578 IN_FLOAT (d = 0.5 * log ((1.0 + d) / (1.0 - d)), "atanh", arg);
579#endif
c2d4ea74
RS
580 return make_float (d);
581}
582
583DEFUN ("cosh", Fcosh, Scosh, 1, 1, 0,
584 "Return the hyperbolic cosine of ARG.")
4b6baf5f
RS
585 (arg)
586 register Lisp_Object arg;
c2d4ea74 587{
4b6baf5f
RS
588 double d = extract_float (arg);
589#ifdef FLOAT_CHECK_DOMAIN
590 if (d > 710.0 || d < -710.0)
591 range_error ("cosh", arg);
592#endif
593 IN_FLOAT (d = cosh (d), "cosh", arg);
c2d4ea74
RS
594 return make_float (d);
595}
596
597DEFUN ("sinh", Fsinh, Ssinh, 1, 1, 0,
598 "Return the hyperbolic sine of ARG.")
4b6baf5f
RS
599 (arg)
600 register Lisp_Object arg;
c2d4ea74 601{
4b6baf5f
RS
602 double d = extract_float (arg);
603#ifdef FLOAT_CHECK_DOMAIN
604 if (d > 710.0 || d < -710.0)
605 range_error ("sinh", arg);
606#endif
607 IN_FLOAT (d = sinh (d), "sinh", arg);
b70021f4
MR
608 return make_float (d);
609}
610
611DEFUN ("tanh", Ftanh, Stanh, 1, 1, 0,
612 "Return the hyperbolic tangent of ARG.")
4b6baf5f
RS
613 (arg)
614 register Lisp_Object arg;
b70021f4 615{
4b6baf5f
RS
616 double d = extract_float (arg);
617 IN_FLOAT (d = tanh (d), "tanh", arg);
b70021f4
MR
618 return make_float (d);
619}
c2d4ea74 620#endif
b70021f4
MR
621\f
622DEFUN ("abs", Fabs, Sabs, 1, 1, 0,
623 "Return the absolute value of ARG.")
4b6baf5f
RS
624 (arg)
625 register Lisp_Object arg;
b70021f4 626{
4b6baf5f 627 CHECK_NUMBER_OR_FLOAT (arg, 0);
b70021f4 628
4b6baf5f
RS
629 if (XTYPE (arg) == Lisp_Float)
630 IN_FLOAT (arg = make_float (fabs (XFLOAT (arg)->data)), "abs", arg);
631 else if (XINT (arg) < 0)
632 XSETINT (arg, - XFASTINT (arg));
b70021f4 633
4b6baf5f 634 return arg;
b70021f4
MR
635}
636
637DEFUN ("float", Ffloat, Sfloat, 1, 1, 0,
638 "Return the floating point number equal to ARG.")
4b6baf5f
RS
639 (arg)
640 register Lisp_Object arg;
b70021f4 641{
4b6baf5f 642 CHECK_NUMBER_OR_FLOAT (arg, 0);
b70021f4 643
4b6baf5f
RS
644 if (XTYPE (arg) == Lisp_Int)
645 return make_float ((double) XINT (arg));
b70021f4 646 else /* give 'em the same float back */
4b6baf5f 647 return arg;
b70021f4
MR
648}
649
650DEFUN ("logb", Flogb, Slogb, 1, 1, 0,
1a3ac8b9 651 "Returns largest integer <= the base 2 log of the magnitude of ARG.\n\
b70021f4 652This is the same as the exponent of a float.")
4b6baf5f
RS
653 (arg)
654 Lisp_Object arg;
b70021f4 655{
340176df 656 Lisp_Object val;
5bf54166
RS
657 int value;
658 double f = extract_float (arg);
340176df 659
6d3c6adb
JB
660#ifdef HAVE_LOGB
661 IN_FLOAT (value = logb (f), "logb", arg);
662 XSET (val, Lisp_Int, value);
663#else
664#ifdef HAVE_FREXP
c26406fe
JB
665 {
666 int exp;
667
668 IN_FLOAT (frexp (f, &exp), "logb", arg);
669 XSET (val, Lisp_Int, exp-1);
670 }
671#else
d3fc9c80
RS
672 /* Would someone like to write code to emulate logb? */
673 error ("`logb' not implemented on this operating system");
6d3c6adb 674#endif
340176df 675#endif
c26406fe
JB
676
677 return val;
b70021f4
MR
678}
679
680/* the rounding functions */
681
682DEFUN ("ceiling", Fceiling, Sceiling, 1, 1, 0,
683 "Return the smallest integer no less than ARG. (Round toward +inf.)")
4b6baf5f
RS
684 (arg)
685 register Lisp_Object arg;
b70021f4 686{
4b6baf5f 687 CHECK_NUMBER_OR_FLOAT (arg, 0);
b70021f4 688
4b6baf5f 689 if (XTYPE (arg) == Lisp_Float)
63a81d88 690 IN_FLOAT (XSET (arg, Lisp_Int, ceil (XFLOAT (arg)->data)), "ceiling", arg);
b70021f4 691
4b6baf5f 692 return arg;
b70021f4
MR
693}
694
fc2157cb
PE
695#endif /* LISP_FLOAT_TYPE */
696
697
698DEFUN ("floor", Ffloor, Sfloor, 1, 2, 0,
699 "Return the largest integer no greater than ARG. (Round towards -inf.)\n\
700With optional DIVISOR, return the largest integer no greater than ARG/DIVISOR.")
701 (arg, divisor)
702 register Lisp_Object arg, divisor;
b70021f4 703{
4b6baf5f 704 CHECK_NUMBER_OR_FLOAT (arg, 0);
b70021f4 705
fc2157cb
PE
706 if (! NILP (divisor))
707 {
708 int i1, i2;
709
710 CHECK_NUMBER_OR_FLOAT (divisor, 1);
711
712#ifdef LISP_FLOAT_TYPE
713 if (XTYPE (arg) == Lisp_Float || XTYPE (divisor) == Lisp_Float)
714 {
715 double f1, f2;
716
717 f1 = XTYPE (arg) == Lisp_Float ? XFLOAT (arg)->data : XINT (arg);
718 f2 = (XTYPE (divisor) == Lisp_Float
719 ? XFLOAT (divisor)->data : XINT (divisor));
720 if (f2 == 0)
721 Fsignal (Qarith_error, Qnil);
722
723 IN_FLOAT2 (XSET (arg, Lisp_Int, floor (f1 / f2)),
724 "floor", arg, divisor);
725 return arg;
726 }
727#endif
728
729 i1 = XINT (arg);
730 i2 = XINT (divisor);
731
732 if (i2 == 0)
733 Fsignal (Qarith_error, Qnil);
734
735 /* With C's /, the result is implementation-defined if either operand
736 is negative, so use only nonnegative operands. */
737 i1 = (i2 < 0
738 ? (i1 <= 0 ? -i1 / -i2 : -1 - ((i1 - 1) / -i2))
739 : (i1 < 0 ? -1 - ((-1 - i1) / i2) : i1 / i2));
740
741 XSET (arg, Lisp_Int, i1);
742 return arg;
743 }
744
745#ifdef LISP_FLOAT_TYPE
4b6baf5f
RS
746 if (XTYPE (arg) == Lisp_Float)
747 IN_FLOAT (XSET (arg, Lisp_Int, floor (XFLOAT (arg)->data)), "floor", arg);
fc2157cb 748#endif
b70021f4 749
4b6baf5f 750 return arg;
b70021f4
MR
751}
752
fc2157cb
PE
753#ifdef LISP_FLOAT_TYPE
754
b70021f4
MR
755DEFUN ("round", Fround, Sround, 1, 1, 0,
756 "Return the nearest integer to ARG.")
4b6baf5f
RS
757 (arg)
758 register Lisp_Object arg;
b70021f4 759{
4b6baf5f 760 CHECK_NUMBER_OR_FLOAT (arg, 0);
b70021f4 761
4b6baf5f
RS
762 if (XTYPE (arg) == Lisp_Float)
763 /* Screw the prevailing rounding mode. */
764 IN_FLOAT (XSET (arg, Lisp_Int, rint (XFLOAT (arg)->data)), "round", arg);
b70021f4 765
4b6baf5f 766 return arg;
b70021f4
MR
767}
768
769DEFUN ("truncate", Ftruncate, Struncate, 1, 1, 0,
770 "Truncate a floating point number to an int.\n\
771Rounds the value toward zero.")
4b6baf5f
RS
772 (arg)
773 register Lisp_Object arg;
b70021f4 774{
4b6baf5f 775 CHECK_NUMBER_OR_FLOAT (arg, 0);
b70021f4 776
4b6baf5f
RS
777 if (XTYPE (arg) == Lisp_Float)
778 XSET (arg, Lisp_Int, (int) XFLOAT (arg)->data);
779
780 return arg;
781}
782\f
783#if 0
784/* It's not clear these are worth adding. */
785
786DEFUN ("fceiling", Ffceiling, Sfceiling, 1, 1, 0,
787 "Return the smallest integer no less than ARG, as a float.\n\
788\(Round toward +inf.\)")
789 (arg)
790 register Lisp_Object arg;
791{
792 double d = extract_float (arg);
793 IN_FLOAT (d = ceil (d), "fceiling", arg);
794 return make_float (d);
795}
796
797DEFUN ("ffloor", Fffloor, Sffloor, 1, 1, 0,
798 "Return the largest integer no greater than ARG, as a float.\n\
799\(Round towards -inf.\)")
800 (arg)
801 register Lisp_Object arg;
802{
803 double d = extract_float (arg);
804 IN_FLOAT (d = floor (d), "ffloor", arg);
805 return make_float (d);
806}
b70021f4 807
4b6baf5f
RS
808DEFUN ("fround", Ffround, Sfround, 1, 1, 0,
809 "Return the nearest integer to ARG, as a float.")
810 (arg)
811 register Lisp_Object arg;
812{
813 double d = extract_float (arg);
814 IN_FLOAT (d = rint (XFLOAT (arg)->data), "fround", arg);
815 return make_float (d);
816}
817
818DEFUN ("ftruncate", Fftruncate, Sftruncate, 1, 1, 0,
819 "Truncate a floating point number to an integral float value.\n\
820Rounds the value toward zero.")
821 (arg)
822 register Lisp_Object arg;
823{
824 double d = extract_float (arg);
825 if (d >= 0.0)
826 IN_FLOAT (d = floor (d), "ftruncate", arg);
827 else
a3fc5236 828 IN_FLOAT (d = ceil (d), "ftruncate", arg);
4b6baf5f 829 return make_float (d);
b70021f4 830}
4b6baf5f 831#endif
b70021f4 832\f
4b6baf5f 833#ifdef FLOAT_CATCH_SIGILL
4746118a 834static SIGTYPE
b70021f4
MR
835float_error (signo)
836 int signo;
837{
838 if (! in_float)
839 fatal_error_signal (signo);
840
265a9e55 841#ifdef BSD
b70021f4
MR
842#ifdef BSD4_1
843 sigrelse (SIGILL);
844#else /* not BSD4_1 */
e065a56e 845 sigsetmask (SIGEMPTYMASK);
b70021f4 846#endif /* not BSD4_1 */
265a9e55
JB
847#else
848 /* Must reestablish handler each time it is called. */
849 signal (SIGILL, float_error);
850#endif /* BSD */
b70021f4
MR
851
852 in_float = 0;
853
854 Fsignal (Qarith_error, Fcons (float_error_arg, Qnil));
855}
856
4b6baf5f
RS
857/* Another idea was to replace the library function `infnan'
858 where SIGILL is signaled. */
859
860#endif /* FLOAT_CATCH_SIGILL */
861
862#ifdef HAVE_MATHERR
863int
864matherr (x)
865 struct exception *x;
866{
867 Lisp_Object args;
868 if (! in_float)
869 /* Not called from emacs-lisp float routines; do the default thing. */
870 return 0;
871 if (!strcmp (x->name, "pow"))
872 x->name = "expt";
873
874 args
875 = Fcons (build_string (x->name),
876 Fcons (make_float (x->arg1),
877 ((!strcmp (x->name, "log") || !strcmp (x->name, "pow"))
878 ? Fcons (make_float (x->arg2), Qnil)
879 : Qnil)));
880 switch (x->type)
881 {
882 case DOMAIN: Fsignal (Qdomain_error, args); break;
883 case SING: Fsignal (Qsingularity_error, args); break;
884 case OVERFLOW: Fsignal (Qoverflow_error, args); break;
885 case UNDERFLOW: Fsignal (Qunderflow_error, args); break;
886 default: Fsignal (Qarith_error, args); break;
887 }
888 return (1); /* don't set errno or print a message */
889}
890#endif /* HAVE_MATHERR */
891
b70021f4
MR
892init_floatfns ()
893{
4b6baf5f 894#ifdef FLOAT_CATCH_SIGILL
b70021f4 895 signal (SIGILL, float_error);
4b6baf5f 896#endif
b70021f4
MR
897 in_float = 0;
898}
899
fc2157cb
PE
900#else /* not LISP_FLOAT_TYPE */
901
902init_floatfns ()
903{}
904
905#endif /* not LISP_FLOAT_TYPE */
906
b70021f4
MR
907syms_of_floatfns ()
908{
fc2157cb 909#ifdef LISP_FLOAT_TYPE
b70021f4 910 defsubr (&Sacos);
b70021f4 911 defsubr (&Sasin);
b70021f4 912 defsubr (&Satan);
c2d4ea74
RS
913 defsubr (&Scos);
914 defsubr (&Ssin);
915 defsubr (&Stan);
916#if 0
917 defsubr (&Sacosh);
918 defsubr (&Sasinh);
b70021f4 919 defsubr (&Satanh);
c2d4ea74
RS
920 defsubr (&Scosh);
921 defsubr (&Ssinh);
922 defsubr (&Stanh);
b70021f4
MR
923 defsubr (&Sbessel_y0);
924 defsubr (&Sbessel_y1);
925 defsubr (&Sbessel_yn);
926 defsubr (&Sbessel_j0);
927 defsubr (&Sbessel_j1);
928 defsubr (&Sbessel_jn);
b70021f4
MR
929 defsubr (&Serf);
930 defsubr (&Serfc);
c2d4ea74 931 defsubr (&Slog_gamma);
4b6baf5f
RS
932 defsubr (&Scube_root);
933 defsubr (&Sfceiling);
934 defsubr (&Sffloor);
935 defsubr (&Sfround);
936 defsubr (&Sftruncate);
c2d4ea74 937#endif
b70021f4 938 defsubr (&Sexp);
c2d4ea74 939 defsubr (&Sexpt);
b70021f4
MR
940 defsubr (&Slog);
941 defsubr (&Slog10);
b70021f4 942 defsubr (&Ssqrt);
b70021f4
MR
943
944 defsubr (&Sabs);
945 defsubr (&Sfloat);
946 defsubr (&Slogb);
947 defsubr (&Sceiling);
b70021f4
MR
948 defsubr (&Sround);
949 defsubr (&Struncate);
fc2157cb
PE
950#endif /* LISP_FLOAT_TYPE */
951 defsubr (&Sfloor);
b70021f4 952}