home *** CD-ROM | disk | FTP | other *** search
- /* largeint.c -- preliminary */
-
- #include <gmp.h>
- #include "mlvalues.h"
- #include "fail.h"
- #include "alloc.h"
-
- /* Arbitrary-precision integers: interface to the GNU
- Multiple-Precision Library GMP.
-
- The type LargeInt.int of arbitrary-precision integers is an
- abstract type; really an MP_INT structure. This will contain a
- pointer to a limb array. The limb array cannot be in camlrunm's
- heap space because the gc cannot understand the MP_INT structure
- (it would be confused by the untagged integer fields).
-
- This raises the question how to deallocate the limb structure when
- it is no longer reachable. One possibility is to use finalized
- objects, calling the mpz_clear function explicitly whenever an
- MP_INT value is about to be garbage-collected by the camlrunm
- runtime.
-
- An largeint should be a finalized object: a pair,
-
- header with Final_tag
- 0: finalization function largeint_clear
- 1: pointer to MP_INT struct
-
- whose component 0 is a pointer to the finalizing function
- largeint_clear, and whose component 1 is a pointer to an MP_INT
- struct. The finalization function should apply mpz_clear to the
- second component of the pair:
- */
-
- #define Large_val(x) (MP_INT*)(Field(x, 1))
-
- void largeint_finalize(obj)
- value obj;
- { MP_INT *mpint;
-
- mpint = Large_val(obj);
- mpz_clear(mpint);
- free(mpint);
- }
-
- /* When the largeint becomes unreachable from the ML process, it will
- be garbage-collected, largeint_finalize() will be called on the
- pointer to the MP_INT struct to deallocate the limbs, and finally
- free() will be called to deallocate the mpint struct itself. The
- camlrunm gc then frees the pair representing the largeint.
-
- Creation of a largeint should call malloc() to allocate an MP_INT
- struct pointed to by mpint, make a finalized pair (largeint_finalize,
- mpint) as described above, and call mpz_init (or similar) on mpint:
- */
-
- value largeint_alloc()
- { MP_INT *mpint;
- value res;
-
- mpint = (MP_INT*)(malloc(sizeof(MP_INT)));
- res = alloc_final(2, &largeint_finalize, 1, 1000);
- Field(res, 1) = (long)mpint;
-
- return res;
- }
-
- void largeint_clear(obj) /* ML */
- value obj;
- { MP_INT *mpint;
-
- largeint_finalize(obj);
- /* This should not be deallocated by the gc also, hence make it
- * abstract: */
- Tag_val(obj) = Abstract_tag;
- }
-
- value largeint_make(null) /* ML */
- value null;
- { value li;
-
- li = largeint_alloc();
- mpz_init(Large_val(li));
- return li;
- }
-
- value largeint_make_si(src) /* ML */
- value src;
- { value li;
-
- li = largeint_alloc();
- mpz_init_set_si(Large_val(li), Long_val(src));
- return li;
- }
-
- value largeint_set(dest, src) /* ML */
- value dest, src;
- { mpz_set(Large_val(dest), Large_val(src));
- return Val_unit;
- }
-
- value largeint_set_si(dest, src) /* ML */
- value dest, src;
- { mpz_set_si(Large_val(dest), Long_val(src));
- return Val_unit;
- }
-
- value largeint_to_si(src) /* ML */
- value src;
- { signed long int tmp;
- value res;
-
- tmp = mpz_get_si(Large_val(src));
- res = Val_long(tmp);
- if (Long_val(res) != tmp)
- { mlraise(Atom(SMLEXN_OVF)); }
- return res;
- }
-
- value largeint_neg(dest, src) /* ML */
- value dest, src;
- { mpz_neg(Large_val(dest), Large_val(src));
- return Val_unit;
- }
-
- value largeint_add(dest, li1, li2) /* ML */
- value dest, li1, li2;
- { mpz_add(Large_val(dest), Large_val(li1), Large_val(li2));
- return Val_unit;
- }
-
- value largeint_sub(dest, li1, li2) /* ML */
- value dest, li1, li2;
- { mpz_sub(Large_val(dest), Large_val(li1), Large_val(li2));
- return Val_unit;
- }
-
- value largeint_mul(dest, li1, li2) /* ML */
- value dest, li1, li2;
- { mpz_mul(Large_val(dest), Large_val(li1), Large_val(li2));
- return Val_unit;
- }
-
- value largeint_mdiv(dest, li1, li2) /* ML */
- value dest, li1, li2;
- { mpz_mdiv(Large_val(dest), Large_val(li1), Large_val(li2));
- return Val_unit;
- }
-
- value largeint_mmod(dest, li1, li2) /* ML */
- value dest, li1, li2;
- { mpz_mmod(Large_val(dest), Large_val(li1), Large_val(li2));
- return Val_unit;
- }
-
- value largeint_div(dest, li1, li2) /* ML */
- value dest, li1, li2;
- { mpz_div(Large_val(dest), Large_val(li1), Large_val(li2));
- return Val_unit;
- }
-
- value largeint_mod(dest, li1, li2) /* ML */
- value dest, li1, li2;
- { mpz_mod(Large_val(dest), Large_val(li1), Large_val(li2));
- return Val_unit;
- }
-
- value largeint_divmod(quotdest, remdest, li1, li2) /* ML */
- value quotdest, remdest, li1, li2;
- { mpz_divmod(Large_val(quotdest), Large_val(remdest),
- Large_val(li1), Large_val(li2));
- return Val_unit;
- }
-
- value largeint_mdivmod(quotdest, remdest, li1, li2) /* ML */
- value quotdest, remdest, li1, li2;
- { mpz_mdivmod(Large_val(quotdest), Large_val(remdest),
- Large_val(li1), Large_val(li2));
- return Val_unit;
- }
-
- value largeint_cmp(li1, li2) /* ML */
- value li1, li2;
- { long res = mpz_cmp(Large_val(li1), Large_val(li2));
- if (res < 0)
- return Val_long(-1);
- else if (res > 0)
- return Val_long(1);
- else
- return Val_long(0);
- }
-
- value largeint_cmp_si(li, si) /* ML */
- value li, si;
- { long res = mpz_cmp_si(Large_val(li), Long_val(si));
- if (res < 0)
- return Val_long(-1);
- else if (res > 0)
- return Val_long(1);
- else
- return Val_long(0);
- }
-
- value largeint_sizeinbase(li, base) /* ML */
- value li, base;
- { return (Val_long(mpz_sizeinbase(Large_val(li), Long_val(base)))); }
-
- /* The mpz_set_str function below is pretty absurd:
- * "- 123" -> ~123
- * " -123" fails
- * "- 12 3" -> ~123
- * "+123" fails
- */
-
- value largeint_set_str(dest, str, base) /* ML */
- value dest, str, base;
- { long res, changesign;
- changesign = (Byte(str, 0) == '~');
- if (changesign) { Byte(str, 0) = '-'; }
- res = mpz_set_str(Large_val(dest), String_val(str), Long_val(base));
- if (changesign) { Byte(str, 0) = '~'; }
- if (0 == res)
- { return Val_unit; }
- else
- { failwith("Illformed number string"); }
- }
-
- value largeint_get_str(src, base) /* ML */
- value src, base;
- { value res;
- long len;
- char *buffer;
-
- len = 3 + mpz_sizeinbase(Large_val(src), Long_val(base));
- buffer = (char*)(malloc(len));
- mpz_get_str(buffer, Long_val(base), Large_val(src));
- res = copy_string(buffer);
- free(buffer);
-
- /* Use the SML sign character: */
- if (Byte(res, 0) == '-')
- { Byte(res, 0) = '~'; }
-
- return res;
- }
-
- value largeint_pow_ui(dest, li, ui) /* ML */
- value dest, li, ui;
- { mpz_pow_ui(Large_val(dest), Large_val(li), Long_val(ui));
- return Val_unit;
- }
-
-