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