2 ent-float.c -- Ordinary Floats for SXEmacs
3 Copyright (C) 2005, 2006 Sebastian Freundt
5 Author: Sebastian Freundt
7 This file is part of SXEmacs
9 SXEmacs is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 SXEmacs is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>. */
27 #include "sysproc.h" /* For qxe_getpid */
32 Lisp_Object Vmost_positive_float;
33 Lisp_Object Vmost_negative_float;
34 Lisp_Object Vleast_positive_float;
35 Lisp_Object Vleast_negative_float;
36 Lisp_Object Vleast_positive_normalised_float;
37 Lisp_Object Vleast_negative_normalised_float;
38 Lisp_Object Vfloat_epsilon;
40 Fixnum max_float_print_size = 0;
44 mark_float(Lisp_Object SXE_UNUSED(obj))
50 float_equal(Lisp_Object obj1, Lisp_Object obj2, int SXE_UNUSED(depth))
52 return (ent_float(obj1) == ent_float(obj2));
55 static inline unsigned long
56 float_hash(Lisp_Object obj, int SXE_UNUSED(depth))
59 fpfloat h = 22.0/7.0*ent_float(obj);
60 union {fpfloat h; long unsigned int hash;} u;
63 return (long unsigned int)u.hash;
65 /* mod the value down to 32-bit range */
66 /* #### change for 64-bit machines */
67 /* WHAT THE FUCK!?! */
68 return (long unsigned int)fmod(ent_float(obj), 4e9);
72 static const struct lrecord_description float_description[] = {
77 print_float(Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
79 char pigbuf[350]; /* see comments in float_to_string */
81 float_to_string(pigbuf, XFLOAT_DATA(obj), sizeof(pigbuf));
82 write_c_string(pigbuf, printcharfun);
85 DEFINE_BASIC_LRECORD_IMPLEMENTATION("float", float,
86 mark_float, print_float, 0, float_equal,
87 float_hash, float_description, Lisp_Float);
90 static inline Lisp_Object
91 ent_sum_FLOAT_T(Lisp_Object l, Lisp_Object r)
93 return make_float(XFLOAT_DATA(l) + XFLOAT_DATA(r));
95 static inline Lisp_Object
96 ent_sum_FLOAT_T_INT_T(Lisp_Object l, Lisp_Object r)
98 return make_float(XFLOAT_DATA(l) + ent_int(r));
100 static inline Lisp_Object
101 ent_sum_INT_T_FLOAT_T(Lisp_Object l, Lisp_Object r)
103 return make_float(ent_int(l) + XFLOAT_DATA(r));
106 static inline Lisp_Object
107 ent_diff_FLOAT_T(Lisp_Object l, Lisp_Object r)
109 return make_float(XFLOAT_DATA(l) - XFLOAT_DATA(r));
111 static inline Lisp_Object
112 ent_diff_FLOAT_T_INT_T(Lisp_Object l, Lisp_Object r)
114 return make_float(XFLOAT_DATA(l) - ent_int(r));
116 static inline Lisp_Object
117 ent_diff_INT_T_FLOAT_T(Lisp_Object l, Lisp_Object r)
119 return make_float(ent_int(l) - XFLOAT_DATA(r));
122 static inline Lisp_Object
123 ent_neg_FLOAT_T(Lisp_Object l)
125 return make_float(-XFLOAT_DATA(l));
128 static inline Lisp_Object
129 ent_prod_FLOAT_T(Lisp_Object l, Lisp_Object r)
131 return make_float(XFLOAT_DATA(l) * XFLOAT_DATA(r));
133 static inline Lisp_Object
134 ent_prod_INT_T_FLOAT_T(Lisp_Object l, Lisp_Object r)
136 return make_float(ent_int(l) * XFLOAT_DATA(r));
138 static inline Lisp_Object
139 ent_prod_FLOAT_T_INT_T(Lisp_Object l, Lisp_Object r)
141 return make_float(XFLOAT_DATA(l) * ent_int(r));
144 static inline Lisp_Object
145 ent_div_FLOAT_T(Lisp_Object l, Lisp_Object r)
147 if (XFLOAT_DATA(r) == 0.0f) {
148 if (XFLOAT_DATA(l) > 0.0f)
149 return make_indef(POS_INFINITY);
150 else if (XFLOAT_DATA(l) < 0.0f)
151 return make_indef(NEG_INFINITY);
153 return make_indef(NOT_A_NUMBER);
155 return make_float(XFLOAT_DATA(l)/XFLOAT_DATA(r));
157 static inline Lisp_Object
158 ent_div_INT_T_FLOAT_T(Lisp_Object l, Lisp_Object r)
160 if (XFLOAT_DATA(r) == 0.0f) {
161 EMACS_INT rl = ent_int(l);
163 return make_indef(POS_INFINITY);
165 return make_indef(NEG_INFINITY);
167 return make_indef(NOT_A_NUMBER);
169 return make_float(ent_int(l)/XFLOAT_DATA(r));
171 static inline Lisp_Object
172 ent_div_FLOAT_T_INT_T(Lisp_Object l, Lisp_Object r)
174 EMACS_INT rr = ent_int(r);
176 if (XFLOAT_DATA(l) > 0.0f)
177 return make_indef(POS_INFINITY);
178 else if (XFLOAT_DATA(l) < 0.0f)
179 return make_indef(NEG_INFINITY);
181 return make_indef(NOT_A_NUMBER);
183 return make_float(XFLOAT_DATA(l)/rr);
186 static inline Lisp_Object
187 ent_rem_FLOAT_T(Lisp_Object SXE_UNUSED(l), Lisp_Object SXE_UNUSED(r))
189 return make_float(0.0);
191 static inline Lisp_Object
192 ent_rem_FLOAT_T_INT_T(Lisp_Object SXE_UNUSED(l), Lisp_Object SXE_UNUSED(r))
194 return make_float(0.0);
197 static inline Lisp_Object
198 ent_mod_FLOAT_T(Lisp_Object l, Lisp_Object r)
202 if (XFLOAT_DATA(r) == 0)
203 Fsignal(Qarith_error, Qnil);
204 rem = fmod(XFLOAT_DATA(l), XFLOAT_DATA(r));
206 /* If the "remainder" comes out with the wrong sign, fix it. */
207 if (XFLOAT_DATA(r) < 0 ? rem > 0 : rem < 0)
208 rem += XFLOAT_DATA(r);
209 return make_float(rem);
211 static inline Lisp_Object
212 ent_mod_FLOAT_T_INT_T(Lisp_Object l, Lisp_Object r)
215 EMACS_INT rr = ent_int(r);
218 Fsignal(Qarith_error, Qnil);
219 rem = fmod(XFLOAT_DATA(l), rr);
221 /* If the "remainder" comes out with the wrong sign, fix it. */
222 if (rr < 0 ? rem > 0 : rem < 0)
224 return make_float(rem);
226 static inline Lisp_Object
227 ent_mod_INT_T_FLOAT_T(Lisp_Object l, Lisp_Object r)
231 if (XFLOAT_DATA(r) == 0)
232 Fsignal(Qarith_error, Qnil);
233 rem = fmod(ent_int(l), XFLOAT_DATA(r));
235 /* If the "remainder" comes out with the wrong sign, fix it. */
236 if (XFLOAT_DATA(r) < 0.0f ? rem > 0.0f : rem < 0.f)
237 rem += XFLOAT_DATA(r);
238 return make_float(rem);
241 static inline Lisp_Object
242 ent_inv_FLOAT_T(Lisp_Object l)
244 if (XFLOAT_DATA(l) == 0.0f) {
245 return make_indef(POS_INFINITY);
247 return make_float(1.0/XFLOAT_DATA(l));
249 static inline Lisp_Object
250 ent_pow_FLOAT_T_integer(Lisp_Object l, Lisp_Object r)
253 fpfloat x = XFLOAT_DATA(l);
254 EMACS_INT y = ent_int(r);
260 retval = (y & 1) ? -1.0 : 1.0;
269 y = (EMACS_UINT) y >> 1;
272 return make_float(retval);
274 static inline Lisp_Object
275 ent_pow_FLOAT_T_float(Lisp_Object l, Lisp_Object r)
277 fpfloat f1 = ent_float(l);
278 fpfloat f2 = ent_float(r);
280 /* Really should check for overflow, too */
281 if (f1 == 0.0 && f2 == 0.0)
282 return make_float(1.0);
283 else if (f1 == 0.0 && f2 < 0.0)
284 Fsignal(Qarith_error, r);
285 else if (f1 < 0 && f2 != floor(f2))
286 Fsignal(Qdomain_error, r);
288 return make_float(pow(f1, f2));
290 return make_float(0.0);
295 ent_lt_float(Lisp_Object l, Lisp_Object r)
297 return (XFLOAT_DATA(l) < XFLOAT_DATA(r));
300 ent_lt_int_float(Lisp_Object l, Lisp_Object r)
302 return (ent_int(l) < XFLOAT_DATA(r));
305 ent_lt_float_int(Lisp_Object l, Lisp_Object r)
307 return (XFLOAT_DATA(l) < ent_int(r));
311 ent_gt_float(Lisp_Object l, Lisp_Object r)
313 return (XFLOAT_DATA(l) > XFLOAT_DATA(r));
316 ent_gt_float_int(Lisp_Object l, Lisp_Object r)
318 return (XFLOAT_DATA(l) > ent_int(r));
321 ent_gt_int_float(Lisp_Object l, Lisp_Object r)
323 return (ent_int(l) > XFLOAT_DATA(r));
327 ent_eq_float(Lisp_Object l, Lisp_Object r)
329 #if defined HAVE_CLEAN_FLOATOPS || 1 /* we wait until this breaks */
330 return (XFLOAT_DATA(l) == XFLOAT_DATA(r));
334 diff = XFLOAT_DATA(l) - XFLOAT_DATA(r);
336 if (diff == (fpfloat)0.0)
338 else if (diff < (fpfloat)0.0 && diff > -XFLOAT_DATA(Vfloat_epsilon))
340 else if (diff > (fpfloat)0.0 && diff < XFLOAT_DATA(Vfloat_epsilon))
347 ent_eq_int_float(Lisp_Object l, Lisp_Object r)
349 return (ent_int(l) == XFLOAT_DATA(r));
352 ent_eq_float_int(Lisp_Object l, Lisp_Object r)
354 return (XFLOAT_DATA(l) == ent_int(r));
358 ent_ne_float(Lisp_Object l, Lisp_Object r)
360 return (XFLOAT_DATA(l) != XFLOAT_DATA(r));
363 ent_ne_int_float(Lisp_Object l, Lisp_Object r)
365 return (ent_int(l) != XFLOAT_DATA(r));
368 ent_ne_float_int(Lisp_Object l, Lisp_Object r)
370 return (XFLOAT_DATA(l) != ent_int(r));
374 static inline Lisp_Object
375 ent_lift_INT_T_FLOAT_T(Lisp_Object number, unsigned long precision)
377 return make_float(ent_int(number));
379 static inline Lisp_Object
380 _ent_lift_INT_T_FLOAT_T(Lisp_Object number, ent_lift_args_t SXE_UNUSED(unused))
382 return make_float(ent_int(number));
385 static inline Lisp_Object
386 ent_lift_FLOAT_T_INT_T(Lisp_Object number, unsigned long precision)
388 return Ftruncate(number);
390 static inline Lisp_Object
391 _ent_lift_FLOAT_T_INT_T(Lisp_Object number, ent_lift_args_t SXE_UNUSED(unused))
393 return Ftruncate(number);
397 ent_float_zerop(Lisp_Object l)
399 return (XFLOAT_DATA(l) == 0.0f);
403 ent_float_onep(Lisp_Object l)
405 return (XFLOAT_DATA(l) == 1.0f);
409 ent_float_unitp(Lisp_Object unused)
415 static ase_nullary_operation_f Qent_float_zero, Qent_float_one;
417 ent_float_nullary_optable_init(void)
419 Qent_float_zero = make_float(0.0f);
420 Qent_float_one = make_float(1.0f);
421 staticpro(&Qent_float_zero);
422 staticpro(&Qent_float_one);
424 ent_nullop_register(ASE_NULLARY_OP_ZERO, FLOAT_T, Qent_float_zero);
425 ent_nullop_register(ASE_NULLARY_OP_ONE, FLOAT_T, Qent_float_one);
429 ent_float_unary_optable_init(void)
431 ent_unop_register(ASE_UNARY_OP_NEG, FLOAT_T, ent_neg_FLOAT_T);
432 ent_unop_register(ASE_UNARY_OP_INV, FLOAT_T, ent_inv_FLOAT_T);
436 ent_float_binary_optable_init(void)
439 ent_binop_register(ASE_BINARY_OP_SUM,
440 FLOAT_T, FLOAT_T, ent_sum_FLOAT_T);
441 ent_binop_register(ASE_BINARY_OP_SUM,
442 FLOAT_T, INT_T, ent_sum_FLOAT_T_INT_T);
443 ent_binop_register(ASE_BINARY_OP_SUM,
444 INT_T, FLOAT_T, ent_sum_INT_T_FLOAT_T);
445 ent_binop_register(ASE_BINARY_OP_DIFF,
446 FLOAT_T, FLOAT_T, ent_diff_FLOAT_T);
447 ent_binop_register(ASE_BINARY_OP_DIFF,
448 FLOAT_T, INT_T, ent_diff_FLOAT_T_INT_T);
449 ent_binop_register(ASE_BINARY_OP_DIFF,
450 INT_T, FLOAT_T, ent_diff_INT_T_FLOAT_T);
453 ent_binop_register(ASE_BINARY_OP_PROD,
454 FLOAT_T, FLOAT_T, ent_prod_FLOAT_T);
455 ent_binop_register(ASE_BINARY_OP_PROD,
456 FLOAT_T, INT_T, ent_prod_FLOAT_T_INT_T);
457 ent_binop_register(ASE_BINARY_OP_PROD,
458 INT_T, FLOAT_T, ent_prod_INT_T_FLOAT_T);
459 ent_binop_register(ASE_BINARY_OP_DIV,
460 FLOAT_T, FLOAT_T, ent_div_FLOAT_T);
461 ent_binop_register(ASE_BINARY_OP_DIV,
462 FLOAT_T, INT_T, ent_div_FLOAT_T_INT_T);
463 ent_binop_register(ASE_BINARY_OP_DIV,
464 INT_T, FLOAT_T, ent_div_INT_T_FLOAT_T);
465 ent_binop_register(ASE_BINARY_OP_QUO,
466 FLOAT_T, FLOAT_T, ent_div_FLOAT_T);
467 ent_binop_register(ASE_BINARY_OP_QUO,
468 FLOAT_T, INT_T, ent_div_FLOAT_T_INT_T);
469 ent_binop_register(ASE_BINARY_OP_QUO,
470 INT_T, FLOAT_T, ent_div_INT_T_FLOAT_T);
473 ent_binop_register(ASE_BINARY_OP_REM,
474 FLOAT_T, FLOAT_T, ent_rem_FLOAT_T);
475 ent_binop_register(ASE_BINARY_OP_REM,
476 FLOAT_T, INT_T, ent_rem_FLOAT_T_INT_T);
477 ent_binop_register(ASE_BINARY_OP_REM,
478 INT_T, FLOAT_T, ent_rem_FLOAT_T);
479 ent_binop_register(ASE_BINARY_OP_MOD,
480 FLOAT_T, FLOAT_T, ent_mod_FLOAT_T);
481 ent_binop_register(ASE_BINARY_OP_MOD,
482 FLOAT_T, INT_T, ent_mod_FLOAT_T_INT_T);
483 ent_binop_register(ASE_BINARY_OP_MOD,
484 INT_T, FLOAT_T, ent_mod_INT_T_FLOAT_T);
486 ent_binop_register(ASE_BINARY_OP_POW,
487 FLOAT_T, INT_T, ent_pow_FLOAT_T_integer);
488 ent_binop_register(ASE_BINARY_OP_POW,
489 FLOAT_T, FLOAT_T, ent_pow_FLOAT_T_float);
493 ent_float_unary_reltable_init(void)
495 ent_unrel_register(ASE_UNARY_REL_ZEROP, FLOAT_T, ent_float_zerop);
496 ent_unrel_register(ASE_UNARY_REL_ONEP, FLOAT_T, ent_float_onep);
497 ent_unrel_register(ASE_UNARY_REL_UNITP, FLOAT_T, ent_float_unitp);
501 ent_float_binary_reltable_init(void)
503 ent_binrel_register(ASE_BINARY_REL_LESSP,
504 FLOAT_T, FLOAT_T, ent_lt_float);
505 ent_binrel_register(ASE_BINARY_REL_LESSP,
506 FLOAT_T, INT_T, ent_lt_float_int);
507 ent_binrel_register(ASE_BINARY_REL_LESSP,
508 INT_T, FLOAT_T, ent_lt_int_float);
509 ent_binrel_register(ASE_BINARY_REL_GREATERP,
510 FLOAT_T, FLOAT_T, ent_gt_float);
511 ent_binrel_register(ASE_BINARY_REL_GREATERP,
512 FLOAT_T, INT_T, ent_gt_float_int);
513 ent_binrel_register(ASE_BINARY_REL_GREATERP,
514 INT_T, FLOAT_T, ent_gt_int_float);
515 ent_binrel_register(ASE_BINARY_REL_EQUALP,
516 FLOAT_T, FLOAT_T, ent_eq_float);
517 ent_binrel_register(ASE_BINARY_REL_EQUALP,
518 FLOAT_T, INT_T, ent_eq_float_int);
519 ent_binrel_register(ASE_BINARY_REL_EQUALP,
520 INT_T, FLOAT_T, ent_eq_int_float);
521 ent_binrel_register(ASE_BINARY_REL_NEQP,
522 FLOAT_T, FLOAT_T, ent_ne_float);
523 ent_binrel_register(ASE_BINARY_REL_NEQP,
524 INT_T, FLOAT_T, ent_ne_int_float);
525 ent_binrel_register(ASE_BINARY_REL_NEQP,
526 FLOAT_T, INT_T, ent_ne_float_int);
530 ent_float_lifttable_init(void)
532 /* lift tables (coercion) */
533 ent_lift_register(INT_T, FLOAT_T, _ent_lift_INT_T_FLOAT_T);
534 ent_lift_register(FLOAT_T, INT_T, _ent_lift_FLOAT_T_INT_T);
535 ent_lift_register(INDEF_T, FLOAT_T, ent_lift_INDEF_T_COMPARABLE);
538 void init_optables_FLOAT_T(void)
540 ent_float_nullary_optable_init();
541 ent_float_unary_optable_init();
542 ent_float_binary_optable_init();
543 ent_float_unary_reltable_init();
544 ent_float_binary_reltable_init();
545 ent_float_lifttable_init();
549 void init_ent_float(void)
553 void syms_of_ent_float(void)
555 INIT_LRECORD_IMPLEMENTATION(float);
558 void vars_of_ent_float(void)
560 fpfloat f = 0.0, fp = 0.0;
564 (f = 2.0 * (fp = f)) &&
565 ! ENT_FLOAT_INDEFINITE_P(f) );
567 DEFVAR_CONST_LISP("most-positive-float", &Vmost_positive_float /*
568 The float closest in value to +infinity.
570 Vmost_positive_float = make_float(fp);
574 (f = 2.0 * (fp = f)) &&
575 ! ENT_FLOAT_INDEFINITE_P(f) );
577 DEFVAR_CONST_LISP("most-negative-float", &Vmost_negative_float /*
578 The float closest in value to -infinity.
580 Vmost_negative_float = make_float(fp);
584 /* let's compute the array we need to print such a float */
586 max_float_print_size = snprintf(tmp, sizeof(tmp), "%f", fp);
587 #elif fpfloat_long_double_p
588 max_float_print_size = snprintf(tmp, sizeof(tmp), "%Lf", fp);
591 assert(max_float_print_size>0);
592 max_float_print_size += 10;
594 DEFVAR_CONST_INT("max-float-print-size", &max_float_print_size /*
595 The maximal string length of a printed float.
600 while ((f = (fp = f) / 2) != 0.0);
601 DEFVAR_CONST_LISP("least-positive-float", &Vleast_positive_float /*
602 The float closest in value to +0.
604 Vleast_positive_float = make_float(fp);
607 while ((f = (fp = f) / 2) != -0.0);
608 DEFVAR_CONST_LISP("least-negative-float", &Vleast_negative_float /*
609 The float closest in value to -0.
611 Vleast_negative_float = make_float(fp);
613 for( f = fp = 1.0; (f /= 2) * 2 == fp && f != 0; fp = f );
614 DEFVAR_CONST_LISP("least-positive-normalised-float",
615 &Vleast_positive_normalised_float /*
616 The float closest in value to +0 without rounding errors.
618 Vleast_positive_normalised_float = make_float(fp);
620 for( f = fp = -1.0; ( f /= 2) * 2 == fp && f != 0; fp = f);
621 DEFVAR_CONST_LISP("least-negative-normalised-float",
622 &Vleast_negative_normalised_float /*
623 The float closest in value to -0 without rounding errors.
625 Vleast_negative_normalised_float = make_float(fp);
627 DEFVAR_CONST_LISP("float-epsilon", &Vfloat_epsilon /*
628 The least positive float which, added to 1, is still greater than 1.
630 #if defined DBL_EPSILON
631 Vfloat_epsilon = make_float(DBL_EPSILON);
632 #else /* !DBL_EPSILON */
634 while ((f = (fp = f) / 2) + 1 != 1);
635 Vfloat_epsilon = make_float(fp);
636 #endif /* DBL_EPSILON */
638 Fprovide(intern("fpfloat"));
639 Fprovide(intern("lisp-float-type"));
642 /* ent-float.c ends here */