Mercurial > hg > xemacs-beta
comparison src/floatfns.c @ 0:376386a54a3c r19-14
Import from CVS: tag r19-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:45:50 +0200 |
parents | |
children | 859a2309aef8 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:376386a54a3c |
---|---|
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_Int if it fits, else signal a range error | |
123 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 | |
163 static Lisp_Object mark_float (Lisp_Object, void (*) (Lisp_Object)); | |
164 extern void print_float (Lisp_Object, Lisp_Object, int); | |
165 static int float_equal (Lisp_Object o1, Lisp_Object o2, int depth); | |
166 static unsigned long float_hash (Lisp_Object obj, int depth); | |
167 DEFINE_BASIC_LRECORD_IMPLEMENTATION ("float", float, | |
168 mark_float, print_float, 0, float_equal, | |
169 float_hash, struct Lisp_Float); | |
170 | |
171 static Lisp_Object | |
172 mark_float (Lisp_Object obj, void (*markobj) (Lisp_Object)) | |
173 { | |
174 return (Qnil); | |
175 } | |
176 | |
177 static int | |
178 float_equal (Lisp_Object o1, Lisp_Object o2, int depth) | |
179 { | |
180 return (extract_float (o1) == extract_float (o2)); | |
181 } | |
182 | |
183 static unsigned long | |
184 float_hash (Lisp_Object obj, int depth) | |
185 { | |
186 /* mod the value down to 32-bit range */ | |
187 /* #### change for 64-bit machines */ | |
188 return (unsigned long) fmod (extract_float (obj), 4e9); | |
189 } | |
190 | |
191 | |
192 /* Extract a Lisp number as a `double', or signal an error. */ | |
193 | |
194 double | |
195 extract_float (Lisp_Object num) | |
196 { | |
197 CHECK_INT_OR_FLOAT (num); | |
198 | |
199 if (FLOATP (num)) | |
200 return (float_data (XFLOAT (num))); | |
201 return (double) XINT (num); | |
202 } | |
203 #endif /* LISP_FLOAT_TYPE */ | |
204 | |
205 | |
206 /* Trig functions. */ | |
207 #ifdef LISP_FLOAT_TYPE | |
208 | |
209 DEFUN ("acos", Facos, Sacos, 1, 1, 0 /* | |
210 Return the inverse cosine of ARG. | |
211 */ ) | |
212 (arg) | |
213 Lisp_Object 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, Sasin, 1, 1, 0 /* | |
225 Return the inverse sine of ARG. | |
226 */ ) | |
227 (arg) | |
228 Lisp_Object arg; | |
229 { | |
230 double d = extract_float (arg); | |
231 #ifdef FLOAT_CHECK_DOMAIN | |
232 if (d > 1.0 || d < -1.0) | |
233 domain_error ("asin", arg); | |
234 #endif | |
235 IN_FLOAT (d = asin (d), "asin", arg); | |
236 return make_float (d); | |
237 } | |
238 | |
239 DEFUN ("atan", Fatan, Satan, 1, 2, 0 /* | |
240 Return the inverse tangent of ARG. | |
241 */ ) | |
242 (arg1, arg2) | |
243 Lisp_Object arg1, arg2; | |
244 { | |
245 double d = extract_float (arg1); | |
246 | |
247 if (NILP (arg2)) | |
248 IN_FLOAT (d = atan (d), "atan", arg1); | |
249 else | |
250 { | |
251 double d2 = extract_float (arg2); | |
252 #ifdef FLOAT_CHECK_DOMAIN | |
253 if (d == 0.0 && d2 == 0.0) | |
254 domain_error2 ("atan", arg1, arg2); | |
255 #endif | |
256 IN_FLOAT2 (d = atan2 (d, d2), "atan", arg1, arg2); | |
257 } | |
258 return make_float (d); | |
259 } | |
260 | |
261 DEFUN ("cos", Fcos, Scos, 1, 1, 0 /* | |
262 Return the cosine of ARG. | |
263 */ ) | |
264 (arg) | |
265 Lisp_Object arg; | |
266 { | |
267 double d = extract_float (arg); | |
268 IN_FLOAT (d = cos (d), "cos", arg); | |
269 return make_float (d); | |
270 } | |
271 | |
272 DEFUN ("sin", Fsin, Ssin, 1, 1, 0 /* | |
273 Return the sine of ARG. | |
274 */ ) | |
275 (arg) | |
276 Lisp_Object arg; | |
277 { | |
278 double d = extract_float (arg); | |
279 IN_FLOAT (d = sin (d), "sin", arg); | |
280 return make_float (d); | |
281 } | |
282 | |
283 DEFUN ("tan", Ftan, Stan, 1, 1, 0 /* | |
284 Return the tangent of ARG. | |
285 */ ) | |
286 (arg) | |
287 Lisp_Object arg; | |
288 { | |
289 double d = extract_float (arg); | |
290 double c = cos (d); | |
291 #ifdef FLOAT_CHECK_DOMAIN | |
292 if (c == 0.0) | |
293 domain_error ("tan", arg); | |
294 #endif | |
295 IN_FLOAT (d = (sin (d) / c), "tan", arg); | |
296 return make_float (d); | |
297 } | |
298 #endif /* LISP_FLOAT_TYPE (trig functions) */ | |
299 | |
300 | |
301 /* Bessel functions */ | |
302 #if 0 /* Leave these out unless we find there's a reason for them. */ | |
303 /* #ifdef LISP_FLOAT_TYPE */ | |
304 | |
305 DEFUN ("bessel-j0", Fbessel_j0, Sbessel_j0, 1, 1, 0 /* | |
306 Return the bessel function j0 of ARG. | |
307 */ ) | |
308 (arg) | |
309 Lisp_Object arg; | |
310 { | |
311 double d = extract_float (arg); | |
312 IN_FLOAT (d = j0 (d), "bessel-j0", arg); | |
313 return make_float (d); | |
314 } | |
315 | |
316 DEFUN ("bessel-j1", Fbessel_j1, Sbessel_j1, 1, 1, 0 /* | |
317 Return the bessel function j1 of ARG. | |
318 */ ) | |
319 (arg) | |
320 Lisp_Object arg; | |
321 { | |
322 double d = extract_float (arg); | |
323 IN_FLOAT (d = j1 (d), "bessel-j1", arg); | |
324 return make_float (d); | |
325 } | |
326 | |
327 DEFUN ("bessel-jn", Fbessel_jn, Sbessel_jn, 2, 2, 0 /* | |
328 Return the order N bessel function output jn of ARG. | |
329 The first arg (the order) is truncated to an integer. | |
330 */ ) | |
331 (arg1, arg2) | |
332 Lisp_Object arg1, arg2; | |
333 { | |
334 int i1 = extract_float (arg1); | |
335 double f2 = extract_float (arg2); | |
336 | |
337 IN_FLOAT (f2 = jn (i1, f2), "bessel-jn", arg1); | |
338 return make_float (f2); | |
339 } | |
340 | |
341 DEFUN ("bessel-y0", Fbessel_y0, Sbessel_y0, 1, 1, 0 /* | |
342 Return the bessel function y0 of ARG. | |
343 */ ) | |
344 (arg) | |
345 Lisp_Object arg; | |
346 { | |
347 double d = extract_float (arg); | |
348 IN_FLOAT (d = y0 (d), "bessel-y0", arg); | |
349 return make_float (d); | |
350 } | |
351 | |
352 DEFUN ("bessel-y1", Fbessel_y1, Sbessel_y1, 1, 1, 0 /* | |
353 Return the bessel function y1 of ARG. | |
354 */ ) | |
355 (arg) | |
356 Lisp_Object arg; | |
357 { | |
358 double d = extract_float (arg); | |
359 IN_FLOAT (d = y1 (d), "bessel-y0", arg); | |
360 return make_float (d); | |
361 } | |
362 | |
363 DEFUN ("bessel-yn", Fbessel_yn, Sbessel_yn, 2, 2, 0 /* | |
364 Return the order N bessel function output yn of ARG. | |
365 The first arg (the order) is truncated to an integer. | |
366 */ ) | |
367 (arg1, arg2) | |
368 Lisp_Object arg1, arg2; | |
369 { | |
370 int i1 = extract_float (arg1); | |
371 double f2 = extract_float (arg2); | |
372 | |
373 IN_FLOAT (f2 = yn (i1, f2), "bessel-yn", arg1); | |
374 return make_float (f2); | |
375 } | |
376 | |
377 #endif /* 0 (bessel functions) */ | |
378 | |
379 /* Error functions. */ | |
380 #if 0 /* Leave these out unless we see they are worth having. */ | |
381 /* #ifdef LISP_FLOAT_TYPE */ | |
382 | |
383 DEFUN ("erf", Ferf, Serf, 1, 1, 0 /* | |
384 Return the mathematical error function of ARG. | |
385 */ ) | |
386 (arg) | |
387 Lisp_Object arg; | |
388 { | |
389 double d = extract_float (arg); | |
390 IN_FLOAT (d = erf (d), "erf", arg); | |
391 return make_float (d); | |
392 } | |
393 | |
394 DEFUN ("erfc", Ferfc, Serfc, 1, 1, 0 /* | |
395 Return the complementary error function of ARG. | |
396 */ ) | |
397 (arg) | |
398 Lisp_Object arg; | |
399 { | |
400 double d = extract_float (arg); | |
401 IN_FLOAT (d = erfc (d), "erfc", arg); | |
402 return make_float (d); | |
403 } | |
404 | |
405 DEFUN ("log-gamma", Flog_gamma, Slog_gamma, 1, 1, 0 /* | |
406 Return the log gamma of ARG. | |
407 */ ) | |
408 (arg) | |
409 Lisp_Object arg; | |
410 { | |
411 double d = extract_float (arg); | |
412 IN_FLOAT (d = lgamma (d), "log-gamma", arg); | |
413 return make_float (d); | |
414 } | |
415 | |
416 #endif /* 0 (error functions) */ | |
417 | |
418 | |
419 /* Root and Log functions. */ | |
420 | |
421 #ifdef LISP_FLOAT_TYPE | |
422 DEFUN ("exp", Fexp, Sexp, 1, 1, 0 /* | |
423 Return the exponential base e of ARG. | |
424 */ ) | |
425 (arg) | |
426 Lisp_Object arg; | |
427 { | |
428 double d = extract_float (arg); | |
429 #ifdef FLOAT_CHECK_DOMAIN | |
430 if (d > 709.7827) /* Assume IEEE doubles here */ | |
431 range_error ("exp", arg); | |
432 else if (d < -709.0) | |
433 return make_float (0.0); | |
434 else | |
435 #endif | |
436 IN_FLOAT (d = exp (d), "exp", arg); | |
437 return make_float (d); | |
438 } | |
439 #endif /* LISP_FLOAT_TYPE */ | |
440 | |
441 | |
442 DEFUN ("expt", Fexpt, Sexpt, 2, 2, 0 /* | |
443 Return the exponential ARG1 ** ARG2. | |
444 */ ) | |
445 (arg1, arg2) | |
446 Lisp_Object arg1, arg2; | |
447 { | |
448 double f1, f2; | |
449 | |
450 CHECK_INT_OR_FLOAT (arg1); | |
451 CHECK_INT_OR_FLOAT (arg2); | |
452 if ((INTP (arg1)) && /* common lisp spec */ | |
453 (INTP (arg2))) /* don't promote, if both are ints */ | |
454 { | |
455 EMACS_INT acc, x, y; | |
456 x = XINT (arg1); | |
457 y = XINT (arg2); | |
458 | |
459 if (y < 0) | |
460 { | |
461 if (x == 1) | |
462 acc = 1; | |
463 else if (x == -1) | |
464 acc = (y & 1) ? -1 : 1; | |
465 else | |
466 acc = 0; | |
467 } | |
468 else | |
469 { | |
470 acc = 1; | |
471 while (y > 0) | |
472 { | |
473 if (y & 1) | |
474 acc *= x; | |
475 x *= x; | |
476 y = (unsigned EMACS_INT) y >> 1; | |
477 } | |
478 } | |
479 return (make_int (acc)); | |
480 } | |
481 #ifdef LISP_FLOAT_TYPE | |
482 f1 = (FLOATP (arg1)) ? float_data (XFLOAT (arg1)) : XINT (arg1); | |
483 f2 = (FLOATP (arg2)) ? float_data (XFLOAT (arg2)) : XINT (arg2); | |
484 /* Really should check for overflow, too */ | |
485 if (f1 == 0.0 && f2 == 0.0) | |
486 f1 = 1.0; | |
487 # ifdef FLOAT_CHECK_DOMAIN | |
488 else if ((f1 == 0.0 && f2 < 0.0) || (f1 < 0 && f2 != floor(f2))) | |
489 domain_error2 ("expt", arg1, arg2); | |
490 # endif /* FLOAT_CHECK_DOMAIN */ | |
491 IN_FLOAT2 (f1 = pow (f1, f2), "expt", arg1, arg2); | |
492 return make_float (f1); | |
493 #else /* !LISP_FLOAT_TYPE */ | |
494 abort (); | |
495 #endif /* LISP_FLOAT_TYPE */ | |
496 } | |
497 | |
498 #ifdef LISP_FLOAT_TYPE | |
499 DEFUN ("log", Flog, Slog, 1, 2, 0 /* | |
500 Return the natural logarithm of ARG. | |
501 If second optional argument BASE is given, return log ARG using that base. | |
502 */ ) | |
503 (arg, base) | |
504 Lisp_Object arg, base; | |
505 { | |
506 double d = extract_float (arg); | |
507 #ifdef FLOAT_CHECK_DOMAIN | |
508 if (d <= 0.0) | |
509 domain_error2 ("log", arg, base); | |
510 #endif | |
511 if (NILP (base)) | |
512 IN_FLOAT (d = log (d), "log", arg); | |
513 else | |
514 { | |
515 double b = extract_float (base); | |
516 #ifdef FLOAT_CHECK_DOMAIN | |
517 if (b <= 0.0 || b == 1.0) | |
518 domain_error2 ("log", arg, base); | |
519 #endif | |
520 if (b == 10.0) | |
521 IN_FLOAT2 (d = log10 (d), "log", arg, base); | |
522 else | |
523 IN_FLOAT2 (d = (log (d) / log (b)), "log", arg, base); | |
524 } | |
525 return make_float (d); | |
526 } | |
527 | |
528 | |
529 DEFUN ("log10", Flog10, Slog10, 1, 1, 0 /* | |
530 Return the logarithm base 10 of ARG. | |
531 */ ) | |
532 (arg) | |
533 Lisp_Object arg; | |
534 { | |
535 double d = extract_float (arg); | |
536 #ifdef FLOAT_CHECK_DOMAIN | |
537 if (d <= 0.0) | |
538 domain_error ("log10", arg); | |
539 #endif | |
540 IN_FLOAT (d = log10 (d), "log10", arg); | |
541 return make_float (d); | |
542 } | |
543 | |
544 | |
545 DEFUN ("sqrt", Fsqrt, Ssqrt, 1, 1, 0 /* | |
546 Return the square root of ARG. | |
547 */ ) | |
548 (arg) | |
549 Lisp_Object arg; | |
550 { | |
551 double d = extract_float (arg); | |
552 #ifdef FLOAT_CHECK_DOMAIN | |
553 if (d < 0.0) | |
554 domain_error ("sqrt", arg); | |
555 #endif | |
556 IN_FLOAT (d = sqrt (d), "sqrt", arg); | |
557 return make_float (d); | |
558 } | |
559 | |
560 | |
561 DEFUN ("cube-root", Fcube_root, Scube_root, 1, 1, 0 /* | |
562 Return the cube root of ARG. | |
563 */ ) | |
564 (arg) | |
565 Lisp_Object arg; | |
566 { | |
567 double d = extract_float (arg); | |
568 #ifdef HAVE_CBRT | |
569 IN_FLOAT (d = cbrt (d), "cube-root", arg); | |
570 #else | |
571 if (d >= 0.0) | |
572 IN_FLOAT (d = pow (d, 1.0/3.0), "cube-root", arg); | |
573 else | |
574 IN_FLOAT (d = -pow (-d, 1.0/3.0), "cube-root", arg); | |
575 #endif | |
576 return make_float (d); | |
577 } | |
578 #endif /* LISP_FLOAT_TYPE */ | |
579 | |
580 | |
581 /* Inverse trig functions. */ | |
582 #ifdef LISP_FLOAT_TYPE | |
583 /* #if 0 Not clearly worth adding... */ | |
584 | |
585 DEFUN ("acosh", Facosh, Sacosh, 1, 1, 0 /* | |
586 Return the inverse hyperbolic cosine of ARG. | |
587 */ ) | |
588 (arg) | |
589 Lisp_Object arg; | |
590 { | |
591 double d = extract_float (arg); | |
592 #ifdef FLOAT_CHECK_DOMAIN | |
593 if (d < 1.0) | |
594 domain_error ("acosh", arg); | |
595 #endif | |
596 #ifdef HAVE_INVERSE_HYPERBOLIC | |
597 IN_FLOAT (d = acosh (d), "acosh", arg); | |
598 #else | |
599 IN_FLOAT (d = log (d + sqrt (d*d - 1.0)), "acosh", arg); | |
600 #endif | |
601 return make_float (d); | |
602 } | |
603 | |
604 DEFUN ("asinh", Fasinh, Sasinh, 1, 1, 0 /* | |
605 Return the inverse hyperbolic sine of ARG. | |
606 */ ) | |
607 (arg) | |
608 Lisp_Object arg; | |
609 { | |
610 double d = extract_float (arg); | |
611 #ifdef HAVE_INVERSE_HYPERBOLIC | |
612 IN_FLOAT (d = asinh (d), "asinh", arg); | |
613 #else | |
614 IN_FLOAT (d = log (d + sqrt (d*d + 1.0)), "asinh", arg); | |
615 #endif | |
616 return make_float (d); | |
617 } | |
618 | |
619 DEFUN ("atanh", Fatanh, Satanh, 1, 1, 0 /* | |
620 Return the inverse hyperbolic tangent of ARG. | |
621 */ ) | |
622 (arg) | |
623 Lisp_Object arg; | |
624 { | |
625 double d = extract_float (arg); | |
626 #ifdef FLOAT_CHECK_DOMAIN | |
627 if (d >= 1.0 || d <= -1.0) | |
628 domain_error ("atanh", arg); | |
629 #endif | |
630 #ifdef HAVE_INVERSE_HYPERBOLIC | |
631 IN_FLOAT (d = atanh (d), "atanh", arg); | |
632 #else | |
633 IN_FLOAT (d = 0.5 * log ((1.0 + d) / (1.0 - d)), "atanh", arg); | |
634 #endif | |
635 return make_float (d); | |
636 } | |
637 | |
638 DEFUN ("cosh", Fcosh, Scosh, 1, 1, 0 /* | |
639 Return the hyperbolic cosine of ARG. | |
640 */ ) | |
641 (arg) | |
642 Lisp_Object arg; | |
643 { | |
644 double d = extract_float (arg); | |
645 #ifdef FLOAT_CHECK_DOMAIN | |
646 if (d > 710.0 || d < -710.0) | |
647 range_error ("cosh", arg); | |
648 #endif | |
649 IN_FLOAT (d = cosh (d), "cosh", arg); | |
650 return make_float (d); | |
651 } | |
652 | |
653 DEFUN ("sinh", Fsinh, Ssinh, 1, 1, 0 /* | |
654 Return the hyperbolic sine of ARG. | |
655 */ ) | |
656 (arg) | |
657 Lisp_Object arg; | |
658 { | |
659 double d = extract_float (arg); | |
660 #ifdef FLOAT_CHECK_DOMAIN | |
661 if (d > 710.0 || d < -710.0) | |
662 range_error ("sinh", arg); | |
663 #endif | |
664 IN_FLOAT (d = sinh (d), "sinh", arg); | |
665 return make_float (d); | |
666 } | |
667 | |
668 DEFUN ("tanh", Ftanh, Stanh, 1, 1, 0 /* | |
669 Return the hyperbolic tangent of ARG. | |
670 */ ) | |
671 (arg) | |
672 Lisp_Object arg; | |
673 { | |
674 double d = extract_float (arg); | |
675 IN_FLOAT (d = tanh (d), "tanh", arg); | |
676 return make_float (d); | |
677 } | |
678 #endif /* LISP_FLOAT_TYPE (inverse trig functions) */ | |
679 | |
680 /* Rounding functions */ | |
681 | |
682 DEFUN ("abs", Fabs, Sabs, 1, 1, 0 /* | |
683 Return the absolute value of ARG. | |
684 */ ) | |
685 (arg) | |
686 Lisp_Object arg; | |
687 { | |
688 CHECK_INT_OR_FLOAT (arg); | |
689 | |
690 #ifdef LISP_FLOAT_TYPE | |
691 if (FLOATP (arg)) | |
692 { | |
693 IN_FLOAT (arg = make_float ((double) fabs (float_data (XFLOAT (arg)))), | |
694 "abs", arg); | |
695 return (arg); | |
696 } | |
697 else | |
698 #endif /* LISP_FLOAT_TYPE */ | |
699 if (XINT (arg) < 0) | |
700 return (make_int (- XINT (arg))); | |
701 else | |
702 return (arg); | |
703 } | |
704 | |
705 #ifdef LISP_FLOAT_TYPE | |
706 DEFUN ("float", Ffloat, Sfloat, 1, 1, 0 /* | |
707 Return the floating point number equal to ARG. | |
708 */ ) | |
709 (arg) | |
710 Lisp_Object arg; | |
711 { | |
712 CHECK_INT_OR_FLOAT (arg); | |
713 | |
714 if (INTP (arg)) | |
715 return make_float ((double) XINT (arg)); | |
716 else /* give 'em the same float back */ | |
717 return arg; | |
718 } | |
719 #endif /* LISP_FLOAT_TYPE */ | |
720 | |
721 | |
722 #ifdef LISP_FLOAT_TYPE | |
723 DEFUN ("logb", Flogb, Slogb, 1, 1, 0 /* | |
724 Return largest integer <= the base 2 log of the magnitude of ARG. | |
725 This is the same as the exponent of a float. | |
726 */ ) | |
727 (arg) | |
728 Lisp_Object arg; | |
729 { | |
730 double f = extract_float (arg); | |
731 | |
732 if (f == 0.0) | |
733 return (make_int (- (((EMACS_UINT) 1) << (VALBITS - 1)))); /* most-negative-fixnum */ | |
734 #ifdef HAVE_LOGB | |
735 { | |
736 Lisp_Object val; | |
737 IN_FLOAT (val = make_int (logb (f)), "logb", arg); | |
738 return (val); | |
739 } | |
740 #else | |
741 #ifdef HAVE_FREXP | |
742 { | |
743 int exqp; | |
744 IN_FLOAT (frexp (f, &exqp), "logb", arg); | |
745 return (make_int (exqp - 1)); | |
746 } | |
747 #else | |
748 { | |
749 int i; | |
750 double d; | |
751 EMACS_INT val; | |
752 if (f < 0.0) | |
753 f = -f; | |
754 val = -1; | |
755 while (f < 0.5) | |
756 { | |
757 for (i = 1, d = 0.5; d * d >= f; i += i) | |
758 d *= d; | |
759 f /= d; | |
760 val -= i; | |
761 } | |
762 while (f >= 1.0) | |
763 { | |
764 for (i = 1, d = 2.0; d * d <= f; i += i) | |
765 d *= d; | |
766 f /= d; | |
767 val += i; | |
768 } | |
769 return (make_int (val)); | |
770 } | |
771 #endif /* ! HAVE_FREXP */ | |
772 #endif /* ! HAVE_LOGB */ | |
773 } | |
774 #endif /* LISP_FLOAT_TYPE */ | |
775 | |
776 | |
777 DEFUN ("ceiling", Fceiling, Sceiling, 1, 1, 0 /* | |
778 Return the smallest integer no less than ARG. (Round toward +inf.) | |
779 */ ) | |
780 (arg) | |
781 Lisp_Object arg; | |
782 { | |
783 CHECK_INT_OR_FLOAT (arg); | |
784 | |
785 #ifdef LISP_FLOAT_TYPE | |
786 if (FLOATP (arg)) | |
787 { | |
788 double d; | |
789 IN_FLOAT ((d = ceil (float_data (XFLOAT (arg)))), "ceiling", arg); | |
790 return (float_to_int (d, "ceiling", arg, Qunbound)); | |
791 } | |
792 #endif /* LISP_FLOAT_TYPE */ | |
793 | |
794 return arg; | |
795 } | |
796 | |
797 | |
798 DEFUN ("floor", Ffloor, Sfloor, 1, 2, 0 /* | |
799 Return the largest integer no greater than ARG. (Round towards -inf.) | |
800 With optional DIVISOR, return the largest integer no greater than ARG/DIVISOR. | |
801 */ ) | |
802 (arg, divisor) | |
803 Lisp_Object arg, divisor; | |
804 { | |
805 CHECK_INT_OR_FLOAT (arg); | |
806 | |
807 if (! NILP (divisor)) | |
808 { | |
809 EMACS_INT i1, i2; | |
810 | |
811 CHECK_INT_OR_FLOAT (divisor); | |
812 | |
813 #ifdef LISP_FLOAT_TYPE | |
814 if (FLOATP (arg) || FLOATP (divisor)) | |
815 { | |
816 double f1, f2; | |
817 | |
818 f1 = ((FLOATP (arg)) ? float_data (XFLOAT (arg)) : XINT (arg)); | |
819 f2 = ((FLOATP (divisor)) ? float_data (XFLOAT (divisor)) : XINT (divisor)); | |
820 if (f2 == 0) | |
821 Fsignal (Qarith_error, Qnil); | |
822 | |
823 IN_FLOAT2 (f1 = floor (f1 / f2), "floor", arg, divisor); | |
824 return float_to_int (f1, "floor", arg, divisor); | |
825 } | |
826 #endif /* LISP_FLOAT_TYPE */ | |
827 | |
828 i1 = XINT (arg); | |
829 i2 = XINT (divisor); | |
830 | |
831 if (i2 == 0) | |
832 Fsignal (Qarith_error, Qnil); | |
833 | |
834 /* With C's /, the result is implementation-defined if either operand | |
835 is negative, so use only nonnegative operands. */ | |
836 i1 = (i2 < 0 | |
837 ? (i1 <= 0 ? -i1 / -i2 : -1 - ((i1 - 1) / -i2)) | |
838 : (i1 < 0 ? -1 - ((-1 - i1) / i2) : i1 / i2)); | |
839 | |
840 return (make_int (i1)); | |
841 } | |
842 | |
843 #ifdef LISP_FLOAT_TYPE | |
844 if (FLOATP (arg)) | |
845 { | |
846 double d; | |
847 IN_FLOAT ((d = floor (float_data (XFLOAT (arg)))), "floor", arg); | |
848 return (float_to_int (d, "floor", arg, Qunbound)); | |
849 } | |
850 #endif /* LISP_FLOAT_TYPE */ | |
851 | |
852 return arg; | |
853 } | |
854 | |
855 DEFUN ("round", Fround, Sround, 1, 1, 0 /* | |
856 Return the nearest integer to ARG. | |
857 */ ) | |
858 (arg) | |
859 Lisp_Object arg; | |
860 { | |
861 CHECK_INT_OR_FLOAT (arg); | |
862 | |
863 #ifdef LISP_FLOAT_TYPE | |
864 if (FLOATP (arg)) | |
865 { | |
866 double d; | |
867 /* Screw the prevailing rounding mode. */ | |
868 IN_FLOAT ((d = rint (float_data (XFLOAT (arg)))), "round", arg); | |
869 return (float_to_int (d, "round", arg, Qunbound)); | |
870 } | |
871 #endif /* LISP_FLOAT_TYPE */ | |
872 | |
873 return arg; | |
874 } | |
875 | |
876 DEFUN ("truncate", Ftruncate, Struncate, 1, 1, 0 /* | |
877 Truncate a floating point number to an integer. | |
878 Rounds the value toward zero. | |
879 */ ) | |
880 (arg) | |
881 Lisp_Object arg; | |
882 { | |
883 CHECK_INT_OR_FLOAT (arg); | |
884 | |
885 #ifdef LISP_FLOAT_TYPE | |
886 if (FLOATP (arg)) | |
887 return (float_to_int (float_data (XFLOAT (arg)), | |
888 "truncate", arg, Qunbound)); | |
889 #endif /* LISP_FLOAT_TYPE */ | |
890 | |
891 return arg; | |
892 } | |
893 | |
894 /* Float-rounding functions. */ | |
895 #ifdef LISP_FLOAT_TYPE | |
896 /* #if 1 It's not clear these are worth adding... */ | |
897 | |
898 DEFUN ("fceiling", Ffceiling, Sfceiling, 1, 1, 0 /* | |
899 Return the smallest integer no less than ARG, as a float. | |
900 \(Round toward +inf.\) | |
901 */ ) | |
902 (arg) | |
903 Lisp_Object arg; | |
904 { | |
905 double d = extract_float (arg); | |
906 IN_FLOAT (d = ceil (d), "fceiling", arg); | |
907 return make_float (d); | |
908 } | |
909 | |
910 DEFUN ("ffloor", Fffloor, Sffloor, 1, 1, 0 /* | |
911 Return the largest integer no greater than ARG, as a float. | |
912 \(Round towards -inf.\) | |
913 */ ) | |
914 (arg) | |
915 Lisp_Object arg; | |
916 { | |
917 double d = extract_float (arg); | |
918 IN_FLOAT (d = floor (d), "ffloor", arg); | |
919 return make_float (d); | |
920 } | |
921 | |
922 DEFUN ("fround", Ffround, Sfround, 1, 1, 0 /* | |
923 Return the nearest integer to ARG, as a float. | |
924 */ ) | |
925 (arg) | |
926 Lisp_Object arg; | |
927 { | |
928 double d = extract_float (arg); | |
929 IN_FLOAT (d = rint (d), "fround", arg); | |
930 return make_float (d); | |
931 } | |
932 | |
933 DEFUN ("ftruncate", Fftruncate, Sftruncate, 1, 1, 0 /* | |
934 Truncate a floating point number to an integral float value. | |
935 Rounds the value toward zero. | |
936 */ ) | |
937 (arg) | |
938 Lisp_Object arg; | |
939 { | |
940 double d = extract_float (arg); | |
941 if (d >= 0.0) | |
942 IN_FLOAT (d = floor (d), "ftruncate", arg); | |
943 else | |
944 IN_FLOAT (d = ceil (d), "ftruncate", arg); | |
945 return make_float (d); | |
946 } | |
947 | |
948 #endif /* LISP_FLOAT_TYPE (float-rounding functions) */ | |
949 | |
950 | |
951 #ifdef LISP_FLOAT_TYPE | |
952 #ifdef FLOAT_CATCH_SIGILL | |
953 static SIGTYPE | |
954 float_error (int signo) | |
955 { | |
956 if (! in_float) | |
957 fatal_error_signal (signo); | |
958 | |
959 EMACS_REESTABLISH_SIGNAL (signo, arith_error); | |
960 EMACS_UNBLOCK_SIGNAL (signo); | |
961 | |
962 in_float = 0; | |
963 | |
964 /* Was Fsignal(), but it just doesn't make sense for an error | |
965 occurring inside a signal handler to be restartable, considering | |
966 that anything could happen when the error is signaled and trapped | |
967 and considering the asynchronous nature of signal handlers. */ | |
968 signal_error (Qarith_error, list1 (float_error_arg)); | |
969 } | |
970 | |
971 /* Another idea was to replace the library function `infnan' | |
972 where SIGILL is signaled. */ | |
973 | |
974 #endif /* FLOAT_CATCH_SIGILL */ | |
975 | |
976 #ifdef HAVE_MATHERR | |
977 int | |
978 matherr (struct exception *x) | |
979 { | |
980 Lisp_Object args; | |
981 if (! in_float) | |
982 /* Not called from emacs-lisp float routines; do the default thing. */ | |
983 return 0; | |
984 | |
985 /* if (!strcmp (x->name, "pow")) x->name = "expt"; */ | |
986 | |
987 args = Fcons (build_string (x->name), | |
988 Fcons (make_float (x->arg1), | |
989 ((in_float == 2) | |
990 ? Fcons (make_float (x->arg2), Qnil) | |
991 : Qnil))); | |
992 switch (x->type) | |
993 { | |
994 case DOMAIN: Fsignal (Qdomain_error, args); break; | |
995 case SING: Fsignal (Qsingularity_error, args); break; | |
996 case OVERFLOW: Fsignal (Qoverflow_error, args); break; | |
997 case UNDERFLOW: Fsignal (Qunderflow_error, args); break; | |
998 default: Fsignal (Qarith_error, args); break; | |
999 } | |
1000 return (1); /* don't set errno or print a message */ | |
1001 } | |
1002 #endif /* HAVE_MATHERR */ | |
1003 #endif /* LISP_FLOAT_TYPE */ | |
1004 | |
1005 | |
1006 void | |
1007 init_floatfns_very_early (void) | |
1008 { | |
1009 #ifdef LISP_FLOAT_TYPE | |
1010 # ifdef FLOAT_CATCH_SIGILL | |
1011 signal (SIGILL, float_error); | |
1012 # endif | |
1013 in_float = 0; | |
1014 #endif /* LISP_FLOAT_TYPE */ | |
1015 } | |
1016 | |
1017 void | |
1018 syms_of_floatfns (void) | |
1019 { | |
1020 | |
1021 /* Trig functions. */ | |
1022 | |
1023 #ifdef LISP_FLOAT_TYPE | |
1024 defsubr (&Sacos); | |
1025 defsubr (&Sasin); | |
1026 defsubr (&Satan); | |
1027 defsubr (&Scos); | |
1028 defsubr (&Ssin); | |
1029 defsubr (&Stan); | |
1030 #endif /* LISP_FLOAT_TYPE */ | |
1031 | |
1032 /* Bessel functions */ | |
1033 | |
1034 #if 0 | |
1035 defsubr (&Sbessel_y0); | |
1036 defsubr (&Sbessel_y1); | |
1037 defsubr (&Sbessel_yn); | |
1038 defsubr (&Sbessel_j0); | |
1039 defsubr (&Sbessel_j1); | |
1040 defsubr (&Sbessel_jn); | |
1041 #endif /* 0 */ | |
1042 | |
1043 /* Error functions. */ | |
1044 | |
1045 #if 0 | |
1046 defsubr (&Serf); | |
1047 defsubr (&Serfc); | |
1048 defsubr (&Slog_gamma); | |
1049 #endif /* 0 */ | |
1050 | |
1051 /* Root and Log functions. */ | |
1052 | |
1053 #ifdef LISP_FLOAT_TYPE | |
1054 defsubr (&Sexp); | |
1055 #endif /* LISP_FLOAT_TYPE */ | |
1056 defsubr (&Sexpt); | |
1057 #ifdef LISP_FLOAT_TYPE | |
1058 defsubr (&Slog); | |
1059 defsubr (&Slog10); | |
1060 defsubr (&Ssqrt); | |
1061 defsubr (&Scube_root); | |
1062 #endif /* LISP_FLOAT_TYPE */ | |
1063 | |
1064 /* Inverse trig functions. */ | |
1065 | |
1066 #ifdef LISP_FLOAT_TYPE | |
1067 defsubr (&Sacosh); | |
1068 defsubr (&Sasinh); | |
1069 defsubr (&Satanh); | |
1070 defsubr (&Scosh); | |
1071 defsubr (&Ssinh); | |
1072 defsubr (&Stanh); | |
1073 #endif /* LISP_FLOAT_TYPE */ | |
1074 | |
1075 /* Rounding functions */ | |
1076 | |
1077 defsubr (&Sabs); | |
1078 #ifdef LISP_FLOAT_TYPE | |
1079 defsubr (&Sfloat); | |
1080 defsubr (&Slogb); | |
1081 #endif /* LISP_FLOAT_TYPE */ | |
1082 defsubr (&Sceiling); | |
1083 defsubr (&Sfloor); | |
1084 defsubr (&Sround); | |
1085 defsubr (&Struncate); | |
1086 | |
1087 /* Float-rounding functions. */ | |
1088 | |
1089 #ifdef LISP_FLOAT_TYPE | |
1090 defsubr (&Sfceiling); | |
1091 defsubr (&Sffloor); | |
1092 defsubr (&Sfround); | |
1093 defsubr (&Sftruncate); | |
1094 #endif /* LISP_FLOAT_TYPE */ | |
1095 } | |
1096 | |
1097 void | |
1098 vars_of_floatfns (void) | |
1099 { | |
1100 #ifdef LISP_FLOAT_TYPE | |
1101 Fprovide (intern ("lisp-float-type")); | |
1102 #endif | |
1103 } |