2 ent-gmp.c -- Numeric types for SXEmacs
3 Copyright (C) 2004 Jerry James
4 Copyright (C) 2004, 2005, 2006 Sebastian Freundt
7 Backport: Sebastian Freundt
9 This file is part of SXEmacs
11 SXEmacs is free software: you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation, either version 3 of the License, or
14 (at your option) any later version.
16 SXEmacs is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>. */
29 #include "sysproc.h" /* For qxe_getpid */
33 static mpf_t float_print_min, float_print_max;
34 gmp_randstate_t random_state;
36 bigz ent_scratch_bigz;
37 bigq ent_scratch_bigq;
38 bigf ent_scratch_bigf;
40 static ase_nullary_operation_f Qent_mpz_zero, Qent_mpz_one;
41 static ase_nullary_operation_f Qent_mpq_zero, Qent_mpq_one;
42 static ase_nullary_operation_f Qent_mpf_zero, Qent_mpf_one;
45 #define yrealloc_array(ptr, type, len) \
46 ((void)(ptr = (type*)yrealloc(ptr, (len) * sizeof(type))))
50 /************************* Big Rational Integers ****************************/
52 bigz_print (Lisp_Object obj, Lisp_Object printcharfun, int SXE_UNUSED(escapeflag))
56 bstr = (Bufbyte*)bigz_to_string(XBIGZ_DATA(obj), 10);
57 write_c_string((char*)bstr, printcharfun);
59 bstr = (Bufbyte *)NULL;
63 bigz_equal (Lisp_Object obj1, Lisp_Object obj2, int SXE_UNUSED(depth))
65 return bigz_eql(XBIGZ_DATA(obj1), XBIGZ_DATA(obj2));
69 bigz_hash (Lisp_Object obj, int SXE_UNUSED(depth))
71 return (unsigned long)bigz_hashcode(XBIGZ_DATA(obj));
74 static const struct lrecord_description bigz_description[] = {
75 { XD_OPAQUE_DATA_PTR, offsetof(Lisp_Bigz, data) },
79 DEFINE_BASIC_LRECORD_IMPLEMENTATION("bigz", bigz,
80 NULL, bigz_print, NULL,
81 bigz_equal, bigz_hash,
82 bigz_description, Lisp_Bigz);
85 /************************** Rational Integer Fractions **********************/
87 bigq_print (Lisp_Object obj, Lisp_Object printcharfun, int SXE_UNUSED(escapeflag))
91 rstr = (Bufbyte*)bigq_to_string(XBIGQ_DATA(obj), 10);
92 write_c_string((char *)rstr, printcharfun);
94 rstr = (Bufbyte *)NULL;
99 bigq_equal (Lisp_Object obj1, Lisp_Object obj2, int SXE_UNUSED(depth))
101 return bigq_eql(XBIGQ_DATA(obj1), XBIGQ_DATA(obj2));
105 bigq_hash (Lisp_Object obj, int SXE_UNUSED(depth))
107 return bigq_hashcode(XBIGQ_DATA(obj));
110 static const struct lrecord_description bigq_description[] = {
111 { XD_OPAQUE_DATA_PTR, offsetof (Lisp_Bigq, data) },
115 DEFINE_BASIC_LRECORD_IMPLEMENTATION("bigq", bigq,
116 NULL, bigq_print, NULL,
117 bigq_equal, bigq_hash,
118 bigq_description, Lisp_Bigq);
121 /********************************** Bigfs ***********************************/
123 bigf_print(Lisp_Object obj, Lisp_Object printcharfun, int SXE_UNUSED(escapeflag))
125 Bufbyte *fstr = bigf_to_string(XBIGF_DATA(obj), 10);
126 write_c_string((char*)fstr, printcharfun);
128 fstr = (Bufbyte *)NULL;
133 bigf_equal(Lisp_Object obj1, Lisp_Object obj2, int SXE_UNUSED(depth))
135 return bigf_eq(XBIGF_DATA(obj1), XBIGF_DATA(obj2));
139 bigf_hash(Lisp_Object obj, int SXE_UNUSED(depth))
141 return bigf_hashcode(XBIGF_DATA(obj));
144 static const struct lrecord_description bigf_description[] = {
145 { XD_OPAQUE_DATA_PTR, offsetof(Lisp_Bigf, data) },
149 DEFINE_BASIC_LRECORD_IMPLEMENTATION("bigf", bigf,
150 NULL, bigf_print, NULL,
151 bigf_equal, bigf_hash,
152 bigf_description, Lisp_Bigf);
154 DEFUN("bigf-get-precision", Fbigf_get_precision, 1, 1, 0, /*
155 Return the precision of bigf F as an integer.
160 return make_integer((signed long)XBIGF_GET_PREC(f));
163 DEFUN("bigf-set-precision", Fbigf_set_precision, 2, 2, 0, /*
164 Set the precision of F, a bigf, to PRECISION, a nonnegative integer.
165 The new precision of F is returned. Note that the return value may differ
166 from PRECISION if the underlying library is unable to support exactly
167 PRECISION bits of precision.
174 if (INTP(precision)) {
175 prec = (XINT(precision) <= 0)
176 ? 1UL : (unsigned long)XINT(precision);
179 else if (BIGZP(precision)) {
180 prec = bigz_fits_ulong_p(XBIGZ_DATA(precision))
181 ? bigz_to_ulong(XBIGZ_DATA(precision))
184 #endif /* HAVE_MPZ */
186 dead_wrong_type_argument(Qintegerp, f);
190 XBIGF_SET_PREC(f, prec);
191 return Fbigf_get_precision(f);
197 bigf_to_string(mpf_t f, int base)
200 Bufbyte *str = (Bufbyte*)mpf_get_str(NULL, &expt, base, 0, f);
201 const int sign = mpf_sgn(f);
202 const int neg = (sign < 0) ? 1 : 0;
203 int len = strlen((char *)str) + 1; /* Count the null terminator */
205 /* Move digits down to insert a radix point */
207 /* We need room for a radix point and leading zeroes */
208 const int space = -expt + 2;
209 xrealloc_array(str, Bufbyte, len + space);
210 memmove(&str[space + neg], &str[neg], len - neg);
211 memset(&str[neg], '0', space);
214 } else if (expt < len) {
215 /* We just need room for a radix point */
216 xrealloc_array(str, Bufbyte, len + 1);
217 memmove(&str[expt + neg + 1],
220 str[expt + neg] = '.';
223 /* We need room for trailing zeroes */
224 xrealloc_array(str, Bufbyte, expt + 1);
225 memset(&str[len-1], '0', expt+2-len);
230 /* never want this here */
231 /* Computerized scientific notation */
232 /* We need room for a radix point, format identifier, and exponent */
233 const int space = (expt < 0)
234 ? (int)(log(-expt) / log(base)) + 3
235 : (int)(log(expt) / log(base)) + 2;
236 xrealloc_array(str, Bufbyte, len + space);
237 memmove(&str[neg + 2], &str[neg + 1], len - neg);
239 sprintf ((char *)&str[len + 2], "%ld", expt);
249 read_bigz_string(const char *cp, int base)
256 /* MPZ bigz_set_string has no effect
257 * with initial + sign */
262 bigz_set_string(bz, (const char*)cp, base);
263 result = make_bigz_bz(bz);
270 Lisp_Object read_bigq_string(char *cp)
277 /* The GMP version of bigq_set_string (mpq_set_str) has the following
279 - If p starts with a '+' sign, it does nothing; i.e., it leaves its
280 ratio argument untouched.
281 - If p has a '+' sign after the '/' (e.g., 300/+400), it sets the
282 numerator from the string, but *leaves the denominator unchanged*.
283 - If p has trailing nonnumeric characters, it sets the numerator from
284 the string, but leaves the denominator unchanged.
285 - If p has more than one '/', (e.g., 1/2/3), then it sets the
286 numerator from the string, but leaves the denominator unchanged.
288 Therefore, move p past any leading '+' signs, temporarily drop a null
289 after the numeric characters we are trying to convert, and then put
290 the nulled character back afterward. I am not going to fix problem
291 #2; just don't write ratios that look like that. */
296 bigq_set_string(bq, cp, 0);
297 bigq_canonicalize(bq);
299 result = ent_mpq_downgrade_maybe(bq);
305 Lisp_Object read_bigf_string(char *cp)
310 bigf_init_prec(bf, internal_get_precision(Qnil));
312 /* The GMP version of bigf_set_string (mpf_set_str)
313 has the following limitation: if p starts with a '+'
314 sign, it does nothing; i.e., it leaves its bigfloat
316 Therefore, move p past any leading '+' signs. */
321 bigf_set_string(bf, cp, 0);
322 result = make_bigf_bf(bf);
330 _ent_mpz_zerop(bigz n)
332 return (bigz_sign(n) == 0);
336 ent_mpz_zerop(Lisp_Object l)
338 return _ent_mpz_zerop(XBIGZ_DATA(l));
342 _ent_mpz_onep(bigz n)
344 return (bigz_fits_long_p(n) && bigz_to_long(n) == 1L);
348 ent_mpz_onep(Lisp_Object l)
350 return _ent_mpz_onep(XBIGZ_DATA(l));
354 _ent_mpz_unitp(bigz n)
356 return (bigz_fits_long_p(n) &&
357 (bigz_to_long(n) == 1L || bigz_to_long(n) == -1L));
361 ent_mpz_unitp(Lisp_Object l)
363 return _ent_mpz_unitp(XBIGZ_DATA(l));
367 ent_sum_BIGZ_T(Lisp_Object l, Lisp_Object r)
369 bigz_add(ent_scratch_bigz, XBIGZ_DATA(l), XBIGZ_DATA(r));
370 return ent_mpz_downgrade_maybe(ent_scratch_bigz);
373 ent_sum_BIGZ_T_INT_T(Lisp_Object l, Lisp_Object r)
375 bigz_set_long(ent_scratch_bigz, ent_int(r));
376 bigz_add(ent_scratch_bigz, XBIGZ_DATA(l), ent_scratch_bigz);
377 return ent_mpz_downgrade_maybe(ent_scratch_bigz);
380 ent_sum_INT_T_BIGZ_T(Lisp_Object l, Lisp_Object r)
382 return ent_sum_BIGZ_T_INT_T(r, l);
386 ent_sum_BIGZ_T_FLOAT_T(Lisp_Object l, Lisp_Object r)
388 return __ent_binop_lift_1(
389 ASE_BINARY_OP_SUM, BIGZ_T, l, FLOAT_T, r, NULL);
392 ent_sum_FLOAT_T_BIGZ_T(Lisp_Object l, Lisp_Object r)
394 return __ent_binop_lift_2(
395 ASE_BINARY_OP_SUM, FLOAT_T, l, BIGZ_T, r, NULL);
400 ent_diff_BIGZ_T(Lisp_Object l, Lisp_Object r)
402 bigz_sub(ent_scratch_bigz, XBIGZ_DATA(l), XBIGZ_DATA(r));
403 return ent_mpz_downgrade_maybe(ent_scratch_bigz);
406 ent_diff_BIGZ_T_INT_T(Lisp_Object l, Lisp_Object r)
408 bigz_set_long(ent_scratch_bigz, ent_int(r));
409 bigz_sub(ent_scratch_bigz, XBIGZ_DATA(l), ent_scratch_bigz);
410 return ent_mpz_downgrade_maybe(ent_scratch_bigz);
413 ent_diff_INT_T_BIGZ_T(Lisp_Object l, Lisp_Object r)
415 bigz_set_long(ent_scratch_bigz, ent_int(l));
416 bigz_sub(ent_scratch_bigz, ent_scratch_bigz, XBIGZ_DATA(r));
417 return ent_mpz_downgrade_maybe(ent_scratch_bigz);
421 ent_diff_BIGZ_T_FLOAT_T(Lisp_Object l, Lisp_Object r)
423 return __ent_binop_lift_1(
424 ASE_BINARY_OP_DIFF, BIGZ_T, l, FLOAT_T, r, NULL);
427 ent_diff_FLOAT_T_BIGZ_T(Lisp_Object l, Lisp_Object r)
429 return __ent_binop_lift_2(
430 ASE_BINARY_OP_DIFF, FLOAT_T, l, BIGZ_T, r, NULL);
435 ent_neg_BIGZ_T(Lisp_Object l)
437 bigz_neg(ent_scratch_bigz, XBIGZ_DATA(l));
438 return make_bigz_bz(ent_scratch_bigz);
442 ent_prod_BIGZ_T(Lisp_Object l, Lisp_Object r)
444 bigz_mul(ent_scratch_bigz, XBIGZ_DATA(l), XBIGZ_DATA(r));
445 return ent_mpz_downgrade_maybe(ent_scratch_bigz);
448 ent_prod_BIGZ_T_INT_T(Lisp_Object l, Lisp_Object r)
450 bigz_set_long(ent_scratch_bigz, ent_int(r));
451 bigz_mul(ent_scratch_bigz, XBIGZ_DATA(l), ent_scratch_bigz);
452 return ent_mpz_downgrade_maybe(ent_scratch_bigz);
455 ent_prod_INT_T_BIGZ_T(Lisp_Object l, Lisp_Object r)
457 return ent_prod_BIGZ_T_INT_T(r, l);
461 ent_prod_BIGZ_T_FLOAT_T(Lisp_Object l, Lisp_Object r)
463 return __ent_binop_lift_1(
464 ASE_BINARY_OP_PROD, BIGZ_T, l, FLOAT_T, r, NULL);
467 ent_prod_FLOAT_T_BIGZ_T(Lisp_Object l, Lisp_Object r)
469 return __ent_binop_lift_2(
470 ASE_BINARY_OP_PROD, FLOAT_T, l, BIGZ_T, r, NULL);
475 ent_div_BIGZ_T(Lisp_Object l, Lisp_Object r)
477 if (bigz_sign(XBIGZ_DATA(r)) == 0) {
478 int lsgn = bigz_sign(XBIGZ_DATA(l));
480 return make_indef(POS_INFINITY);
482 return make_indef(NEG_INFINITY);
484 return make_indef(NOT_A_NUMBER);
486 bigz_div(ent_scratch_bigz, XBIGZ_DATA(l), XBIGZ_DATA(r));
487 return ent_mpz_downgrade_maybe(ent_scratch_bigz);
490 ent_div_BIGZ_T_INT_T(Lisp_Object l, Lisp_Object r)
492 if (ent_int(r) == 0) {
493 int lsgn = bigz_sign(XBIGZ_DATA(l));
495 return make_indef(POS_INFINITY);
497 return make_indef(NEG_INFINITY);
499 return make_indef(NOT_A_NUMBER);
502 bigz_set_long(ent_scratch_bigz, ent_int(r));
503 bigz_div(ent_scratch_bigz, XBIGZ_DATA(l), ent_scratch_bigz);
504 return ent_mpz_downgrade_maybe(ent_scratch_bigz);
507 ent_div_INT_T_BIGZ_T(Lisp_Object l, Lisp_Object r)
509 if (bigz_sign(XBIGZ_DATA(r)) == 0) {
510 EMACS_INT rl = ent_int(l);
512 return make_indef(POS_INFINITY);
514 return make_indef(NEG_INFINITY);
516 return make_indef(NOT_A_NUMBER);
519 bigz_set_long(ent_scratch_bigz, ent_int(l));
520 bigz_div(ent_scratch_bigz, ent_scratch_bigz, XBIGZ_DATA(r));
521 return ent_mpz_downgrade_maybe(ent_scratch_bigz);
525 ent_div_BIGZ_T_FLOAT_T(Lisp_Object l, Lisp_Object r)
527 return __ent_binop_lift_1(
528 ASE_BINARY_OP_DIV, BIGZ_T, l, FLOAT_T, r, NULL);
531 ent_div_FLOAT_T_BIGZ_T(Lisp_Object l, Lisp_Object r)
533 return __ent_binop_lift_2(
534 ASE_BINARY_OP_DIV, FLOAT_T, l, BIGZ_T, r, NULL);
539 ent_quo_BIGZ_T(Lisp_Object l, Lisp_Object r)
541 if (bigz_sign(XBIGZ_DATA(r)) == 0) {
542 int lsgn = bigz_sign(XBIGZ_DATA(l));
544 return make_indef(POS_INFINITY);
546 return make_indef(NEG_INFINITY);
548 return make_indef(NOT_A_NUMBER);
551 bigq_set_bigz_bigz(ent_scratch