Mercurial > hg > xemacs-beta
comparison src/floatfns.c @ 428:3ecd8885ac67 r21-2-22
Import from CVS: tag r21-2-22
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:28:15 +0200 |
parents | |
children | a5df635868b2 |
comparison
equal
deleted
inserted
replaced
427:0a0253eac470 | 428:3ecd8885ac67 |
---|---|
1 /* Primitive operations on floating point for XEmacs Lisp interpreter. | |
2 Copyright (C) 1988, 1993, 1994 Free Software Foundation, Inc. | |
3 | |
4 This file is part of XEmacs. | |
5 | |
6 XEmacs is free software; you can redistribute it and/or modify it | |
7 under the terms of the GNU General Public License as published by the | |
8 Free Software Foundation; either version 2, or (at your option) any | |
9 later version. | |
10 | |
11 XEmacs is distributed in the hope that it will be useful, but WITHOUT | |
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
14 for more details. | |
15 | |
16 You should have received a copy of the GNU General Public License | |
17 along with XEmacs; see the file COPYING. If not, write to | |
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
19 Boston, MA 02111-1307, USA. */ | |
20 | |
21 /* Synched up with: FSF 19.30. */ | |
22 | |
23 /* ANSI C requires only these float functions: | |
24 acos, asin, atan, atan2, ceil, cos, cosh, exp, fabs, floor, fmod, | |
25 frexp, ldexp, log, log10, modf, pow, sin, sinh, sqrt, tan, tanh. | |
26 | |
27 Define HAVE_INVERSE_HYPERBOLIC if you have acosh, asinh, and atanh. | |
28 Define HAVE_CBRT if you have cbrt(). | |
29 Define HAVE_RINT if you have rint(). | |
30 If you don't define these, then the appropriate routines will be simulated. | |
31 | |
32 Define HAVE_MATHERR if on a system supporting the SysV matherr() callback. | |
33 (This should happen automatically.) | |
34 | |
35 Define FLOAT_CHECK_ERRNO if the float library routines set errno. | |
36 This has no effect if HAVE_MATHERR is defined. | |
37 | |
38 Define FLOAT_CATCH_SIGILL if the float library routines signal SIGILL. | |
39 (What systems actually do this? Let me know. -jwz) | |
40 | |
41 Define FLOAT_CHECK_DOMAIN if the float library doesn't handle errors by | |
42 either setting errno, or signalling SIGFPE/SIGILL. Otherwise, domain and | |
43 range checking will happen before calling the float routines. This has | |
44 no effect if HAVE_MATHERR is defined (since matherr will be called when | |
45 a domain error occurs). | |
46 */ | |
47 | |
48 #include <config.h> | |
49 #include "lisp.h" | |
50 #include "syssignal.h" | |
51 | |
52 #ifdef LISP_FLOAT_TYPE | |
53 | |
54 /* Need to define a differentiating symbol -- see sysfloat.h */ | |
55 #define THIS_FILENAME floatfns | |
56 #include "sysfloat.h" | |
57 | |
58 #ifndef HAVE_RINT | |
59 static double | |
60 rint (double x) | |
61 { | |
62 double r = floor (x + 0.5); | |
63 double diff = fabs (r - x); | |
64 /* Round to even and correct for any roundoff errors. */ | |
65 if (diff >= 0.5 && (diff > 0.5 || r != 2.0 * floor (r / 2.0))) | |
66 r += r < x ? 1.0 : -1.0; | |
67 return r; | |
68 } | |
69 #endif | |
70 | |
71 /* Nonzero while executing in floating point. | |
72 This tells float_error what to do. */ | |
73 static int in_float; | |
74 | |
75 /* If an argument is out of range for a mathematical function, | |
76 here is the actual argument value to use in the error message. */ | |
77 static Lisp_Object float_error_arg, float_error_arg2; | |
78 static CONST char *float_error_fn_name; | |
79 | |
80 /* Evaluate the floating point expression D, recording NUM | |
81 as the original argument for error messages. | |
82 D is normally an assignment expression. | |
83 Handle errors which may result in signals or may set errno. | |
84 | |
85 Note that float_error may be declared to return void, so you can't | |
86 just cast the zero after the colon to (SIGTYPE) to make the types | |
87 check properly. */ | |
88 #ifdef FLOAT_CHECK_ERRNO | |
89 #define IN_FLOAT(d, name, num) \ | |
90 do { \ | |
91 float_error_arg = num; \ | |
92 float_error_fn_name = name; \ | |
93 in_float = 1; errno = 0; (d); in_float = 0; \ | |
94 if (errno != 0) in_float_error (); \ | |
95 } while (0) | |
96 #define IN_FLOAT2(d, name, num, num2) \ | |
97 do { \ | |
98 float_error_arg = num; \ | |
99 float_error_arg2 = num2; \ | |
100 float_error_fn_name = name; \ | |
101 in_float = 2; errno = 0; (d); in_float = 0; \ | |
102 if (errno != 0) in_float_error (); \ | |
103 } while (0) | |
104 #else | |
105 #define IN_FLOAT(d, name, num) (in_float = 1, (d), in_float = 0) | |
106 #define IN_FLOAT2(d, name, num, num2) (in_float = 2, (d), in_float = 0) | |
107 #endif | |
108 | |
109 | |
110 #define arith_error(op,arg) \ | |
111 Fsignal (Qarith_error, list2 (build_string (op), arg)) | |
112 #define range_error(op,arg) \ | |
113 Fsignal (Qrange_error, list2 (build_string (op), arg)) | |
114 #define range_error2(op,a1,a2) \ | |
115 Fsignal (Qrange_error, list3 (build_string (op), a1, a2)) | |
116 #define domain_error(op,arg) \ | |
117 Fsignal (Qdomain_error, list2 (build_string (op), arg)) | |
118 #define domain_error2(op,a1,a2) \ | |
119 Fsignal (Qdomain_error, list3 (build_string (op), a1, a2)) | |
120 | |
121 | |
122 /* Convert float to Lisp Integer if it fits, else signal a range | |
123 error using the given arguments. */ | |
124 static Lisp_Object | |
125 float_to_int (double x, CONST char *name, Lisp_Object num, Lisp_Object num2) | |
126 { | |
127 if (x >= ((EMACS_INT) 1 << (VALBITS-1)) | |
128 || x <= - ((EMACS_INT) 1 << (VALBITS-1)) - (EMACS_INT) 1) | |
129 { | |
130 if (!UNBOUNDP (num2)) | |
131 range_error2 (name, num, num2); | |
132 else | |
133 range_error (name, num); | |
134 } | |
135 return (make_int ((EMACS_INT) x)); | |
136 } | |
137 | |
138 | |
139 static void | |
140 in_float_error (void) | |
141 { | |
142 switch (errno) | |
143 { | |
144 case 0: | |
145 break; | |
146 case EDOM: | |
147 if (in_float == 2) | |
148 domain_error2 (float_error_fn_name, float_error_arg, float_error_arg2); | |
149 else | |
150 domain_error (float_error_fn_name, float_error_arg); | |
151 break; | |
152 case ERANGE: | |
153 range_error (float_error_fn_name, float_error_arg); | |
154 break; | |
155 default: | |
156 arith_error (float_error_fn_name, float_error_arg); | |
157 break; | |
158 } | |
159 } | |
160 | |
161 | |
162 static Lisp_Object | |
163 mark_float (Lisp_Object obj) | |
164 { | |
165 return Qnil; | |
166 } | |
167 | |
168 static int | |
169 float_equal (Lisp_Object obj1, Lisp_Object obj2, int depth) | |
170 { | |
171 return (extract_float (obj1) == extract_float (obj2)); | |
172 } | |
173 | |
174 static unsigned long | |
175 float_hash (Lisp_Object obj, int depth) | |
176 { | |
177 /* mod the value down to 32-bit range */ | |
178 /* #### change for 64-bit machines */ | |
179 return (unsigned long) fmod (extract_float (obj), 4e9); | |
180 } | |
181 | |
182 static const struct lrecord_description float_description[] = { | |
183 { XD_END } | |
184 }; | |
185 | |
186 DEFINE_BASIC_LRECORD_IMPLEMENTATION ("float", float, | |
187 mark_float, print_float, 0, float_equal, | |
188 float_hash, float_description, | |
189 struct Lisp_Float); | |
190 | |
191 /* Extract a Lisp number as a `double', or signal an error. */ | |
192 | |
193 double | |
194 extract_float (Lisp_Object num) | |
195 { | |
196 if (FLOATP (num)) | |
197 return XFLOAT_DATA (num); | |
198 | |
199 if (INTP (num)) | |
200 return (double) XINT (num); | |
201 | |
202 return extract_float (wrong_type_argument (Qnumberp, num)); | |
203 } | |
204 #endif /* LISP_FLOAT_TYPE */ | |
205 | |
206 | |
207 /* Trig functions. */ | |
208 #ifdef LISP_FLOAT_TYPE | |
209 | |
210 DEFUN ("acos", Facos, 1, 1, 0, /* | |
211 Return the inverse cosine of ARG. | |
212 */ | |
213 (arg)) | |
214 { | |
215 double d = extract_float (arg); | |
216 #ifdef FLOAT_CHECK_DOMAIN | |
217 if (d > 1.0 || d < -1.0) | |
218 domain_error ("acos", arg); | |
219 #endif | |
220 IN_FLOAT (d = acos (d), "acos", arg); | |
221 return make_float (d); | |
222 } | |
223 | |
224 DEFUN ("asin", Fasin, 1, 1, 0, /* | |
225 Return the inverse sine of ARG. | |
226 */ | |
227 (arg)) | |
228 { | |
229 double d = extract_float (arg); | |
230 #ifdef FLOAT_CHECK_DOMAIN | |
231 if (d > 1.0 || d < -1.0) | |
232 domain_error ("asin", arg); | |
233 #endif | |
234 IN_FLOAT (d = asin (d), "asin", arg); | |
235 return make_float (d); | |
236 } | |
237 | |
238 DEFUN ("atan", Fatan, 1, 2, 0, /* | |
239 Return the inverse tangent of ARG. | |
240 */ | |
241 (arg1, arg2)) | |
242 { | |
243 double d = extract_float (arg1); | |
244 | |
245 if (NILP (arg2)) | |
246 IN_FLOAT (d = atan (d), "atan", arg1); | |
247 else | |
248 { | |
249 double d2 = extract_float (arg2); | |
250 #ifdef FLOAT_CHECK_DOMAIN | |
251 if (d == 0.0 && d2 == 0.0) | |
252 domain_error2 ("atan", arg1, arg2); | |
253 #endif | |
254 IN_FLOAT2 (d = atan2 (d, d2), "atan", arg1, arg2); | |
255 } | |
256 return make_float (d); | |
257 } | |
258 | |
259 DEFUN ("cos", Fcos, 1, 1, 0, /* | |
260 Return the cosine of ARG. | |
261 */ | |
262 (arg)) | |
263 { | |
264 double d = extract_float (arg); | |
265 IN_FLOAT (d = cos (d), "cos", arg); | |
266 return make_float (d); | |
267 } | |
268 | |
269 DEFUN ("sin", Fsin, 1, 1, 0, /* | |
270 Return the sine of ARG. | |
271 */ | |
272 (arg)) | |
273 { | |
274 double d = extract_float (arg); | |
275 IN_FLOAT (d = sin (d), "sin", arg); | |
276 return make_float (d); | |
277 } | |
278 | |
279 DEFUN ("tan", Ftan, 1, 1, 0, /* | |
280 Return the tangent of ARG. | |
281 */ | |
282 (arg)) | |
283 { | |
284 double d = extract_float (arg); | |
285 double c = cos (d); | |
286 #ifdef FLOAT_CHECK_DOMAIN | |
287 if (c == 0.0) | |
288 domain_error ("tan", arg); | |
289 #endif | |
290 IN_FLOAT (d = (sin (d) / c), "tan", arg); | |
291 return make_float (d); | |
292 } | |
293 #endif /* LISP_FLOAT_TYPE (trig functions) */ | |
294 | |
295 | |
296 /* Bessel functions */ | |
297 #if 0 /* Leave these out unless we find there's a reason for them. */ | |
298 /* #ifdef LISP_FLOAT_TYPE */ | |
299 | |
300 DEFUN ("bessel-j0", Fbessel_j0, 1, 1, 0, /* | |
301 Return the bessel function j0 of ARG. | |
302 */ | |
303 (arg)) | |
304 { | |
305 double d = extract_float (arg); | |
306 IN_FLOAT (d = j0 (d), "bessel-j0", arg); | |
307 return make_float (d); | |
308 } | |
309 | |
310 DEFUN ("bessel-j1", Fbessel_j1, 1, 1, 0, /* | |
311 Return the bessel function j1 of ARG. | |
312 */ | |
313 (arg)) | |
314 { | |
315 double d = extract_float (arg); | |
316 IN_FLOAT (d = j1 (d), "bessel-j1", arg); | |
317 return make_float (d); | |
318 } | |
319 | |
320 DEFUN ("bessel-jn", Fbessel_jn, 2, 2, 0, /* | |
321 Return the order N bessel function output jn of ARG. | |
322 The first arg (the order) is truncated to an integer. | |
323 */ | |
324 (arg1, arg2)) | |
325 { | |
326 int i1 = extract_float (arg1); | |
327 double f2 = extract_float (arg2); | |
328 | |
329 IN_FLOAT (f2 = jn (i1, f2), "bessel-jn", arg1); | |
330 return make_float (f2); | |
331 } | |
332 | |
333 DEFUN ("bessel-y0", Fbessel_y0, 1, 1, 0, /* | |
334 Return the bessel function y0 of ARG. | |
335 */ | |
336 (arg)) | |
337 { | |
338 double d = extract_float (arg); | |
339 IN_FLOAT (d = y0 (d), "bessel-y0", arg); | |
340 return make_float (d); | |
341 } | |
342 | |
343 DEFUN ("bessel-y1", Fbessel_y1, 1, 1, 0, /* | |
344 Return the bessel function y1 of ARG. | |
345 */ | |
346 (arg)) | |
347 { | |
348 double d = extract_float (arg); | |
349 IN_FLOAT (d = y1 (d), "bessel-y0", arg); | |
350 return make_float (d); | |
351 } | |
352 | |
353 DEFUN ("bessel-yn", Fbessel_yn, 2, 2, 0, /* | |
354 Return the order N bessel function output yn of ARG. | |
355 The first arg (the order) is truncated to an integer. | |
356 */ | |
357 (arg1, arg2)) | |
358 { | |
359 int i1 = extract_float (arg1); | |
360 double f2 = extract_float (arg2); | |
361 | |
362 IN_FLOAT (f2 = yn (i1, f2), "bessel-yn", arg1); | |
363 return make_float (f2); | |
364 } | |
365 | |
366 #endif /* 0 (bessel functions) */ | |
367 | |
368 /* Error functions. */ | |
369 #if 0 /* Leave these out unless we see they are worth having. */ | |
370 /* #ifdef LISP_FLOAT_TYPE */ | |
371 | |
372 DEFUN ("erf", Ferf, 1, 1, 0, /* | |
373 Return the mathematical error function of ARG. | |
374 */ | |
375 (arg)) | |
376 { | |
377 double d = extract_float (arg); | |
378 IN_FLOAT (d = erf (d), "erf", arg); | |
379 return make_float (d); | |
380 } | |
381 | |
382 DEFUN ("erfc", Ferfc, 1, 1, 0, /* | |
383 Return the complementary error function of ARG. | |
384 */ | |
385 (arg)) | |
386 { | |
387 double d = extract_float (arg); | |
388 IN_FLOAT (d = erfc (d), "erfc", arg); | |
389 return make_float (d); | |
390 } | |
391 | |
392 DEFUN ("log-gamma", Flog_gamma, 1, 1, 0, /* | |
393 Return the log gamma of ARG. | |
394 */ | |
395 (arg)) | |
396 { | |
397 double d = extract_float (arg); | |
398 IN_FLOAT (d = lgamma (d), "log-gamma", arg); | |
399 return make_float (d); | |
400 } | |
401 | |
402 #endif /* 0 (error functions) */ | |
403 | |
404 | |
405 /* Root and Log functions. */ | |
406 | |
407 #ifdef LISP_FLOAT_TYPE | |
408 DEFUN ("exp", Fexp, 1, 1, 0, /* | |
409 Return the exponential base e of ARG. | |
410 */ | |
411 (arg)) | |
412 { | |
413 double d = extract_float (arg); | |
414 #ifdef FLOAT_CHECK_DOMAIN | |
415 if (d > 709.7827) /* Assume IEEE doubles here */ | |
416 range_error ("exp", arg); | |
417 else if (d < -709.0) | |
418 return make_float (0.0); | |
419 else | |
420 #endif | |
421 IN_FLOAT (d = exp (d), "exp", arg); | |
422 return make_float (d); | |
423 } | |
424 #endif /* LISP_FLOAT_TYPE */ | |
425 | |
426 | |
427 DEFUN ("expt", Fexpt, 2, 2, 0, /* | |
428 Return the exponential ARG1 ** ARG2. | |
429 */ | |
430 (arg1, arg2)) | |
431 { | |
432 if (INTP (arg1) && /* common lisp spec */ | |
433 INTP (arg2)) /* don't promote, if both are ints */ | |
434 { | |
435 EMACS_INT retval; | |
436 EMACS_INT x = XINT (arg1); | |
437 EMACS_INT y = XINT (arg2); | |
438 | |
439 if (y < 0) | |
440 { | |
441 if (x == 1) | |
442 retval = 1; | |
443 else if (x == -1) | |
444 retval = (y & 1) ? -1 : 1; | |
445 else | |
446 retval = 0; | |
447 } | |
448 else | |
449 { | |
450 retval = 1; | |
451 while (y > 0) | |
452 { | |
453 if (y & 1) | |
454 retval *= x; | |
455 x *= x; | |
456 y = (EMACS_UINT) y >> 1; | |
457 } | |
458 } | |
459 return make_int (retval); | |
460 } | |
461 | |
462 #ifdef LISP_FLOAT_TYPE | |
463 { | |
464 double f1 = extract_float (arg1); | |
465 double f2 = extract_float (arg2); | |
466 /* Really should check for overflow, too */ | |
467 if (f1 == 0.0 && f2 == 0.0) | |
468 f1 = 1.0; | |
469 # ifdef FLOAT_CHECK_DOMAIN | |
470 else if ((f1 == 0.0 && f2 < 0.0) || (f1 < 0 && f2 != floor(f2))) | |
471 domain_error2 ("expt", arg1, arg2); | |
472 # endif /* FLOAT_CHECK_DOMAIN */ | |
473 IN_FLOAT2 (f1 = pow (f1, f2), "expt", arg1, arg2); | |
474 return make_float (f1); | |
475 } | |
476 #else | |
477 CHECK_INT_OR_FLOAT (arg1); | |
478 CHECK_INT_OR_FLOAT (arg2); | |
479 return Fexpt (arg1, arg2); | |
480 #endif /* LISP_FLOAT_TYPE */ | |
481 } | |
482 | |
483 #ifdef LISP_FLOAT_TYPE | |
484 DEFUN ("log", Flog, 1, 2, 0, /* | |
485 Return the natural logarithm of ARG. | |
486 If second optional argument BASE is given, return log ARG using that base. | |
487 */ | |
488 (arg, base)) | |
489 { | |
490 double d = extract_float (arg); | |
491 #ifdef FLOAT_CHECK_DOMAIN | |
492 if (d <= 0.0) | |
493 domain_error2 ("log", arg, base); | |
494 #endif | |
495 if (NILP (base)) | |
496 IN_FLOAT (d = log (d), "log", arg); | |
497 else | |
498 { | |
499 double b = extract_float (base); | |
500 #ifdef FLOAT_CHECK_DOMAIN | |
501 if (b <= 0.0 || b == 1.0) | |
502 domain_error2 ("log", arg, base); | |
503 #endif | |
504 if (b == 10.0) | |
505 IN_FLOAT2 (d = log10 (d), "log", arg, base); | |
506 else | |
507 IN_FLOAT2 (d = (log (d) / log (b)), "log", arg, base); | |
508 } | |
509 return make_float (d); | |
510 } | |
511 | |
512 | |
513 DEFUN ("log10", Flog10, 1, 1, 0, /* | |
514 Return the logarithm base 10 of ARG. | |
515 */ | |
516 (arg)) | |
517 { | |
518 double d = extract_float (arg); | |
519 #ifdef FLOAT_CHECK_DOMAIN | |
520 if (d <= 0.0) | |
521 domain_error ("log10", arg); | |
522 #endif | |
523 IN_FLOAT (d = log10 (d), "log10", arg); | |
524 return make_float (d); | |
525 } | |
526 | |
527 | |
528 DEFUN ("sqrt", Fsqrt, 1, 1, 0, /* | |
529 Return the square root of ARG. | |
530 */ | |
531 (arg)) | |
532 { | |
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); | |
539 return make_float (d); | |
540 } | |
541 | |
542 | |
543 DEFUN ("cube-root", Fcube_root, 1, 1, 0, /* | |
544 Return the cube root of ARG. | |
545 */ | |
546 (arg)) | |
547 { | |
548 double d = extract_float (arg); | |
549 #ifdef HAVE_CBRT | |
550 IN_FLOAT (d = cbrt (d), "cube-root", arg); | |
551 #else | |
552 if (d >= 0.0) | |
553 IN_FLOAT (d = pow (d, 1.0/3.0), "cube-root", arg); | |
554 else | |
555 IN_FLOAT (d = -pow (-d, 1.0/3.0), "cube-root", arg); | |
556 #endif | |
557 return make_float (d); | |
558 } | |
559 #endif /* LISP_FLOAT_TYPE */ | |
560 | |
561 | |
562 /* Inverse trig functions. */ | |
563 #ifdef LISP_FLOAT_TYPE | |
564 /* #if 0 Not clearly worth adding... */ | |
565 | |
566 DEFUN ("acosh", Facosh, 1, 1, 0, /* | |
567 Return the inverse hyperbolic cosine of ARG. | |
568 */ | |
569 (arg)) | |
570 { | |
571 double d = extract_float (arg); | |
572 #ifdef FLOAT_CHECK_DOMAIN | |
573 if (d < 1.0) | |
574 domain_error ("acosh", arg); | |
575 #endif | |
576 #ifdef HAVE_INVERSE_HYPERBOLIC | |
577 IN_FLOAT (d = acosh (d), "acosh", arg); | |
578 #else | |
579 IN_FLOAT (d = log (d + sqrt (d*d - 1.0)), "acosh", arg); | |
580 #endif | |
581 return make_float (d); | |
582 } | |
583 | |
584 DEFUN ("asinh", Fasinh, 1, 1, 0, /* | |
585 Return the inverse hyperbolic sine of ARG. | |
586 */ | |
587 (arg)) | |
588 { | |
589 double d = extract_float (arg); | |
590 #ifdef HAVE_INVERSE_HYPERBOLIC | |
591 IN_FLOAT (d = asinh (d), "asinh", arg); | |
592 #else | |
593 IN_FLOAT (d = log (d + sqrt (d*d + 1.0)), "asinh", arg); | |
594 #endif | |
595 return make_float (d); | |
596 } | |
597 | |
598 DEFUN ("atanh", Fatanh, 1, 1, 0, /* | |
599 Return the inverse hyperbolic tangent of ARG. | |
600 */ | |
601 (arg)) | |
602 { | |
603 double d = extract_float (arg); | |
604 #ifdef FLOAT_CHECK_DOMAIN | |
605 if (d >= 1.0 || d <= -1.0) | |
606 domain_error ("atanh", arg); | |
607 #endif | |
608 #ifdef HAVE_INVERSE_HYPERBOLIC | |
609 IN_FLOAT (d = atanh (d), "atanh", arg); | |
610 #else | |
611 IN_FLOAT (d = 0.5 * log ((1.0 + d) / (1.0 - d)), "atanh", arg); | |
612 #endif | |
613 return make_float (d); | |
614 } | |
615 | |
616 DEFUN ("cosh", Fcosh, 1, 1, 0, /* | |
617 Return the hyperbolic cosine of ARG. | |
618 */ | |
619 (arg)) | |
620 { | |
621 double d = extract_float (arg); | |
622 #ifdef FLOAT_CHECK_DOMAIN | |
623 if (d > 710.0 || d < -710.0) | |
624 range_error ("cosh", arg); | |
625 #endif | |
626 IN_FLOAT (d = cosh (d), "cosh", arg); | |
627 return make_float (d); | |
628 } | |
629 | |
630 DEFUN ("sinh", Fsinh, 1, 1, 0, /* | |
631 Return the hyperbolic sine of ARG. | |
632 */ | |
633 (arg)) | |
634 { | |
635 double d = extract_float (arg); | |
636 #ifdef FLOAT_CHECK_DOMAIN | |
637 if (d > 710.0 || d < -710.0) | |
638 range_error ("sinh", arg); | |
639 #endif | |
640 IN_FLOAT (d = sinh (d), "sinh", arg); | |
641 return make_float (d); | |
642 } | |
643 | |
644 DEFUN ("tanh", Ftanh, 1, 1, 0, /* | |
645 Return the hyperbolic tangent of ARG. | |
646 */ | |
647 (arg)) | |
648 { | |
649 double d = extract_float (arg); | |
650 IN_FLOAT (d = tanh (d), "tanh", arg); | |
651 return make_float (d); | |
652 } | |
653 #endif /* LISP_FLOAT_TYPE (inverse trig functions) */ | |
654 | |
655 /* Rounding functions */ | |
656 | |
657 DEFUN ("abs", Fabs, 1, 1, 0, /* | |
658 Return the absolute value of ARG. | |
659 */ | |
660 (arg)) | |
661 { | |
662 #ifdef LISP_FLOAT_TYPE | |
663 if (FLOATP (arg)) | |
664 { | |
665 IN_FLOAT (arg = make_float (fabs (XFLOAT_DATA (arg))), | |
666 "abs", arg); | |
667 return arg; | |
668 } | |
669 #endif /* LISP_FLOAT_TYPE */ | |
670 | |
671 if (INTP (arg)) | |
672 return (XINT (arg) >= 0) ? arg : make_int (- XINT (arg)); | |
673 | |
674 return Fabs (wrong_type_argument (Qnumberp, arg)); | |
675 } | |
676 | |
677 #ifdef LISP_FLOAT_TYPE | |
678 DEFUN ("float", Ffloat, 1, 1, 0, /* | |
679 Return the floating point number numerically equal to ARG. | |
680 */ | |
681 (arg)) | |
682 { | |
683 if (INTP (arg)) | |
684 return make_float ((double) XINT (arg)); | |
685 | |
686 if (FLOATP (arg)) /* give 'em the same float back */ | |
687 return arg; | |
688 | |
689 return Ffloat (wrong_type_argument (Qnumberp, arg)); | |
690 } | |
691 #endif /* LISP_FLOAT_TYPE */ | |
692 | |
693 | |
694 #ifdef LISP_FLOAT_TYPE | |
695 DEFUN ("logb", Flogb, 1, 1, 0, /* | |
696 Return largest integer <= the base 2 log of the magnitude of ARG. | |
697 This is the same as the exponent of a float. | |
698 */ | |
699 (arg)) | |
700 { | |
701 double f = extract_float (arg); | |
702 | |
703 if (f == 0.0) | |
704 return make_int (- (int)((((EMACS_UINT) 1) << (VALBITS - 1)))); /* most-negative-fixnum */ | |
705 #ifdef HAVE_LOGB | |
706 { | |
707 Lisp_Object val; | |
708 IN_FLOAT (val = make_int ((int) logb (f)), "logb", arg); | |
709 return (val); | |
710 } | |
711 #else | |
712 #ifdef HAVE_FREXP | |
713 { | |
714 int exqp; | |
715 IN_FLOAT (frexp (f, &exqp), "logb", arg); | |
716 return (make_int (exqp - 1)); | |
717 } | |
718 #else | |
719 { | |
720 int i; | |
721 double d; | |
722 EMACS_INT val; | |
723 if (f < 0.0) | |
724 f = -f; | |
725 val = -1; | |
726 while (f < 0.5) | |
727 { | |
728 for (i = 1, d = 0.5; d * d >= f; i += i) | |
729 d *= d; | |
730 f /= d; | |
731 val -= i; | |
732 } | |
733 while (f >= 1.0) | |
734 { | |
735 for (i = 1, d = 2.0; d * d <= f; i += i) | |
736 d *= d; | |
737 f /= d; | |
738 val += i; | |
739 } | |
740 return (make_int (val)); | |
741 } | |
742 #endif /* ! HAVE_FREXP */ | |
743 #endif /* ! HAVE_LOGB */ | |
744 } | |
745 #endif /* LISP_FLOAT_TYPE */ | |
746 | |
747 | |
748 DEFUN ("ceiling", Fceiling, 1, 1, 0, /* | |
749 Return the smallest integer no less than ARG. (Round toward +inf.) | |
750 */ | |
751 (arg)) | |
752 { | |
753 #ifdef LISP_FLOAT_TYPE | |
754 if (FLOATP (arg)) | |
755 { | |
756 double d; | |
757 IN_FLOAT ((d = ceil (XFLOAT_DATA (arg))), "ceiling", arg); | |
758 return (float_to_int (d, "ceiling", arg, Qunbound)); | |
759 } | |
760 #endif /* LISP_FLOAT_TYPE */ | |
761 | |
762 if (INTP (arg)) | |
763 return arg; | |
764 | |
765 return Fceiling (wrong_type_argument (Qnumberp, arg)); | |
766 } | |
767 | |
768 | |
769 DEFUN ("floor", Ffloor, 1, 2, 0, /* | |
770 Return the largest integer no greater than ARG. (Round towards -inf.) | |
771 With optional DIVISOR, return the largest integer no greater than ARG/DIVISOR. | |
772 */ | |
773 (arg, divisor)) | |
774 { | |
775 CHECK_INT_OR_FLOAT (arg); | |
776 | |
777 if (! NILP (divisor)) | |
778 { | |
779 EMACS_INT i1, i2; | |
780 | |
781 CHECK_INT_OR_FLOAT (divisor); | |
782 | |
783 #ifdef LISP_FLOAT_TYPE | |
784 if (FLOATP (arg) || FLOATP (divisor)) | |
785 { | |
786 double f1 = extract_float (arg); | |
787 double f2 = extract_float (divisor); | |
788 | |
789 if (f2 == 0) | |
790 Fsignal (Qarith_error, Qnil); | |
791 | |
792 IN_FLOAT2 (f1 = floor (f1 / f2), "floor", arg, divisor); | |
793 return float_to_int (f1, "floor", arg, divisor); | |
794 } | |
795 #endif /* LISP_FLOAT_TYPE */ | |
796 | |
797 i1 = XINT (arg); | |
798 i2 = XINT (divisor); | |
799 | |
800 if (i2 == 0) | |
801 Fsignal (Qarith_error, Qnil); | |
802 | |
803 /* With C's /, the result is implementation-defined if either operand | |
804 is negative, so use only nonnegative operands. */ | |
805 i1 = (i2 < 0 | |
806 ? (i1 <= 0 ? -i1 / -i2 : -1 - ((i1 - 1) / -i2)) | |
807 : (i1 < 0 ? -1 - ((-1 - i1) / i2) : i1 / i2)); | |
808 | |
809 return (make_int (i1)); | |
810 } | |
811 | |
812 #ifdef LISP_FLOAT_TYPE | |
813 if (FLOATP (arg)) | |
814 { | |
815 double d; | |
816 IN_FLOAT ((d = floor (XFLOAT_DATA (arg))), "floor", arg); | |
817 return (float_to_int (d, "floor", arg, Qunbound)); | |
818 } | |
819 #endif /* LISP_FLOAT_TYPE */ | |
820 | |
821 return arg; | |
822 } | |
823 | |
824 DEFUN ("round", Fround, 1, 1, 0, /* | |
825 Return the nearest integer to ARG. | |
826 */ | |
827 (arg)) | |
828 { | |
829 #ifdef LISP_FLOAT_TYPE | |
830 if (FLOATP (arg)) | |
831 { | |
832 double d; | |
833 /* Screw the prevailing rounding mode. */ | |
834 IN_FLOAT ((d = rint (XFLOAT_DATA (arg))), "round", arg); | |
835 return (float_to_int (d, "round", arg, Qunbound)); | |
836 } | |
837 #endif /* LISP_FLOAT_TYPE */ | |
838 | |
839 if (INTP (arg)) | |
840 return arg; | |
841 | |
842 return Fround (wrong_type_argument (Qnumberp, arg)); | |
843 } | |
844 | |
845 DEFUN ("truncate", Ftruncate, 1, 1, 0, /* | |
846 Truncate a floating point number to an integer. | |
847 Rounds the value toward zero. | |
848 */ | |
849 (arg)) | |
850 { | |
851 #ifdef LISP_FLOAT_TYPE | |
852 if (FLOATP (arg)) | |
853 return float_to_int (XFLOAT_DATA (arg), "truncate", arg, Qunbound); | |
854 #endif /* LISP_FLOAT_TYPE */ | |
855 | |
856 if (INTP (arg)) | |
857 return arg; | |
858 | |
859 return Ftruncate (wrong_type_argument (Qnumberp, arg)); | |
860 } | |
861 | |
862 /* Float-rounding functions. */ | |
863 #ifdef LISP_FLOAT_TYPE | |
864 /* #if 1 It's not clear these are worth adding... */ | |
865 | |
866 DEFUN ("fceiling", Ffceiling, 1, 1, 0, /* | |
867 Return the smallest integer no less than ARG, as a float. | |
868 \(Round toward +inf.\) | |
869 */ | |
870 (arg)) | |
871 { | |
872 double d = extract_float (arg); | |
873 IN_FLOAT (d = ceil (d), "fceiling", arg); | |
874 return make_float (d); | |
875 } | |
876 | |
877 DEFUN ("ffloor", Fffloor, 1, 1, 0, /* | |
878 Return the largest integer no greater than ARG, as a float. | |
879 \(Round towards -inf.\) | |
880 */ | |
881 (arg)) | |
882 { | |
883 double d = extract_float (arg); | |
884 IN_FLOAT (d = floor (d), "ffloor", arg); | |
885 return make_float (d); | |
886 } | |
887 | |
888 DEFUN ("fround", Ffround, 1, 1, 0, /* | |
889 Return the nearest integer to ARG, as a float. | |
890 */ | |
891 (arg)) | |
892 { | |
893 double d = extract_float (arg); | |
894 IN_FLOAT (d = rint (d), "fround", arg); | |
895 return make_float (d); | |
896 } | |
897 | |
898 DEFUN ("ftruncate", Fftruncate, 1, 1, 0, /* | |
899 Truncate a floating point number to an integral float value. | |
900 Rounds the value toward zero. | |
901 */ | |
902 (arg)) | |
903 { | |
904 double d = extract_float (arg); | |
905 if (d >= 0.0) | |
906 IN_FLOAT (d = floor (d), "ftruncate", arg); | |
907 else | |
908 IN_FLOAT (d = ceil (d), "ftruncate", arg); | |
909 return make_float (d); | |
910 } | |
911 | |
912 #endif /* LISP_FLOAT_TYPE (float-rounding functions) */ | |
913 | |
914 | |
915 #ifdef LISP_FLOAT_TYPE | |
916 #ifdef FLOAT_CATCH_SIGILL | |
917 static SIGTYPE | |
918 float_error (int signo) | |
919 { | |
920 if (! in_float) | |
921 fatal_error_signal (signo); | |
922 | |
923 EMACS_REESTABLISH_SIGNAL (signo, arith_error); | |
924 EMACS_UNBLOCK_SIGNAL (signo); | |
925 | |
926 in_float = 0; | |
927 | |
928 /* Was Fsignal(), but it just doesn't make sense for an error | |
929 occurring inside a signal handler to be restartable, considering | |
930 that anything could happen when the error is signaled and trapped | |
931 and considering the asynchronous nature of signal handlers. */ | |
932 signal_error (Qarith_error, list1 (float_error_arg)); | |
933 } | |
934 | |
935 /* Another idea was to replace the library function `infnan' | |
936 where SIGILL is signaled. */ | |
937 | |
938 #endif /* FLOAT_CATCH_SIGILL */ | |
939 | |
940 /* In C++, it is impossible to determine what type matherr expects | |
941 without some more configure magic. | |
942 We shouldn't be using matherr anyways - it's a non-standard SYSVism. */ | |
943 #if defined (HAVE_MATHERR) && !defined(__cplusplus) | |
944 int | |
945 matherr (struct exception *x) | |
946 { | |
947 Lisp_Object args; | |
948 if (! in_float) | |
949 /* Not called from emacs-lisp float routines; do the default thing. */ | |
950 return 0; | |
951 | |
952 /* if (!strcmp (x->name, "pow")) x->name = "expt"; */ | |
953 | |
954 args = Fcons (build_string (x->name), | |
955 Fcons (make_float (x->arg1), | |
956 ((in_float == 2) | |
957 ? Fcons (make_float (x->arg2), Qnil) | |
958 : Qnil))); | |
959 switch (x->type) | |
960 { | |
961 case DOMAIN: Fsignal (Qdomain_error, args); break; | |
962 case SING: Fsignal (Qsingularity_error, args); break; | |
963 case OVERFLOW: Fsignal (Qoverflow_error, args); break; | |
964 case UNDERFLOW: Fsignal (Qunderflow_error, args); break; | |
965 default: Fsignal (Qarith_error, args); break; | |
966 } | |
967 return 1; /* don't set errno or print a message */ | |
968 } | |
969 #endif /* HAVE_MATHERR */ | |
970 #endif /* LISP_FLOAT_TYPE */ | |
971 | |
972 | |
973 void | |
974 init_floatfns_very_early (void) | |
975 { | |
976 #ifdef LISP_FLOAT_TYPE | |
977 # ifdef FLOAT_CATCH_SIGILL | |
978 signal (SIGILL, float_error); | |
979 # endif | |
980 in_float = 0; | |
981 #endif /* LISP_FLOAT_TYPE */ | |
982 } | |
983 | |
984 void | |
985 syms_of_floatfns (void) | |
986 { | |
987 | |
988 /* Trig functions. */ | |
989 | |
990 #ifdef LISP_FLOAT_TYPE | |
991 DEFSUBR (Facos); | |
992 DEFSUBR (Fasin); | |
993 DEFSUBR (Fatan); | |
994 DEFSUBR (Fcos); | |
995 DEFSUBR (Fsin); | |
996 DEFSUBR (Ftan); | |
997 #endif /* LISP_FLOAT_TYPE */ | |
998 | |
999 /* Bessel functions */ | |
1000 | |
1001 #if 0 | |
1002 DEFSUBR (Fbessel_y0); | |
1003 DEFSUBR (Fbessel_y1); | |
1004 DEFSUBR (Fbessel_yn); | |
1005 DEFSUBR (Fbessel_j0); | |
1006 DEFSUBR (Fbessel_j1); | |
1007 DEFSUBR (Fbessel_jn); | |
1008 #endif /* 0 */ | |
1009 | |
1010 /* Error functions. */ | |
1011 | |
1012 #if 0 | |
1013 DEFSUBR (Ferf); | |
1014 DEFSUBR (Ferfc); | |
1015 DEFSUBR (Flog_gamma); | |
1016 #endif /* 0 */ | |
1017 | |
1018 /* Root and Log functions. */ | |
1019 | |
1020 #ifdef LISP_FLOAT_TYPE | |
1021 DEFSUBR (Fexp); | |
1022 #endif /* LISP_FLOAT_TYPE */ | |
1023 DEFSUBR (Fexpt); | |
1024 #ifdef LISP_FLOAT_TYPE | |
1025 DEFSUBR (Flog); | |
1026 DEFSUBR (Flog10); | |
1027 DEFSUBR (Fsqrt); | |
1028 DEFSUBR (Fcube_root); | |
1029 #endif /* LISP_FLOAT_TYPE */ | |
1030 | |
1031 /* Inverse trig functions. */ | |
1032 | |
1033 #ifdef LISP_FLOAT_TYPE | |
1034 DEFSUBR (Facosh); | |
1035 DEFSUBR (Fasinh); | |
1036 DEFSUBR (Fatanh); | |
1037 DEFSUBR (Fcosh); | |
1038 DEFSUBR (Fsinh); | |
1039 DEFSUBR (Ftanh); | |
1040 #endif /* LISP_FLOAT_TYPE */ | |
1041 | |
1042 /* Rounding functions */ | |
1043 | |
1044 DEFSUBR (Fabs); | |
1045 #ifdef LISP_FLOAT_TYPE | |
1046 DEFSUBR (Ffloat); | |
1047 DEFSUBR (Flogb); | |
1048 #endif /* LISP_FLOAT_TYPE */ | |
1049 DEFSUBR (Fceiling); | |
1050 DEFSUBR (Ffloor); | |
1051 DEFSUBR (Fround); | |
1052 DEFSUBR (Ftruncate); | |
1053 | |
1054 /* Float-rounding functions. */ | |
1055 | |
1056 #ifdef LISP_FLOAT_TYPE | |
1057 DEFSUBR (Ffceiling); | |
1058 DEFSUBR (Fffloor); | |
1059 DEFSUBR (Ffround); | |
1060 DEFSUBR (Fftruncate); | |
1061 #endif /* LISP_FLOAT_TYPE */ | |
1062 } | |
1063 | |
1064 void | |
1065 vars_of_floatfns (void) | |
1066 { | |
1067 #ifdef LISP_FLOAT_TYPE | |
1068 Fprovide (intern ("lisp-float-type")); | |
1069 #endif | |
1070 } |