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