This is an automated email from the git hooks/post-receive script. glondu pushed a commit to branch master in repository ocaml-zarith.
commit f0827a1c06b2667dbdd8efd207be9e8261b0f13f Author: Stephane Glondu <st...@glondu.net> Date: Fri Sep 22 15:08:34 2017 +0200 New upstream version 1.5 --- .gitignore | 10 +++++ Changes | 13 +++++- META | 2 +- Makefile | 25 ----------- README | 130 ------------------------------------------------------- README.md | 126 +++++++++++++++++++++++++++++++++++++++++++++++++++++ caml_z.c | 6 +-- project.mak | 7 +-- q.ml | 36 ++++++++++++++- q.mli | 5 +++ tests/bi.ml | 14 +++--- tests/tofloat.ml | 80 ++++++++++++++++++++++++++-------- z.mlip | 52 +++++++++++++--------- z.mlp | 30 ++++++------- z_pp.pl | 8 ++++ 15 files changed, 320 insertions(+), 224 deletions(-) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..afef917 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +*.a +*.cm? +*.cmxa +*.cmxs +*.exe +*.o +Makefile +z.ml +z.mli +z_features.h diff --git a/Changes b/Changes index 7f16b4d..2ddfaa2 100644 --- a/Changes +++ b/Changes @@ -1,3 +1,14 @@ +Release 1.5 (2017-05-26): +- Install all .cmx files, improving performance of clients and + avoiding a warning from OCaml 4.03 and up. +- Z.of_float: fix a bug in the fast path [Richard Jones] + (See https://bugzilla.redhat.com/show_bug.cgi?id=1392247) +- Improve compatibility with OCaml 4.03 and up + [Bernhard Schommer] +- Overflow issue in Z.pow and Z.root with very large exponents (GPR#5) + [Andre Maroneze] +- Added function Q.to_float. + Release 1.4.1 (2015-11-09): - Fixed ml_z_of_substring_base and Z.of_substring [Thomas Braibant] - Integrated Opam fix for Perl scripts [Thomas Braibant] @@ -12,7 +23,7 @@ Release 1.4 (2015-11-02): - Added Z.trailing_zeros. - Added Z.testbit, Z.is_even, Z.is_odd. - Added Z.numbits, Z.log2 and Z.log2up. -- PR$1467: Z.hash is declared as "noalloc" [François Bobot] +- PR#1467: Z.hash is declared as "noalloc" [François Bobot] - PR#1451: configure fix [Spiros Eliopoulos] - PR#1436: disable "(void)" trick for unused variables on Windows [Bernhard Schommer] - PR#1434: removed dependencies on printf & co when Z_PERFORM_CHECK is 0 [Hannes Mehnert] diff --git a/META b/META index 854de4b..d2aeb02 100644 --- a/META +++ b/META @@ -1,5 +1,5 @@ description = "Arbitrary precision integers" requires = "" -version = "1.4.1" +version = "1.5" archive(byte) = "zarith.cma" archive(native) = "zarith.cmxa" diff --git a/Makefile b/Makefile deleted file mode 100644 index 7c4c31f..0000000 --- a/Makefile +++ /dev/null @@ -1,25 +0,0 @@ -# generated by ./configure - -CC=gcc -OCAMLC=ocamlc -OCAMLOPT=ocamlopt -OCAMLDEP=ocamldep -OCAMLMKLIB=ocamlmklib -OCAMLDOC=ocamldoc -OCAMLFLAGS= -OCAMLOPTFLAGS= -OCAMLINC= -CFLAGS=-I/home/mine/.opam/4.02.1/lib/ocaml -DZ_OCAML_HASH -DZ_OCAML_COMPARE_EXT -DHAS_GMP -DZ_ELF -DZ_DOT_LABEL_PREFIX -O3 -Wall -Wextra -I/home/mine/include -I/usr/local/include -ASFLAGS=-DZ_OCAML_HASH -DZ_OCAML_COMPARE_EXT -DHAS_GMP -DZ_ELF -DZ_DOT_LABEL_PREFIX -LIBS=-L/home/mine/lib -L/usr/local/lib -lgmp -ARCH=x86_64 -INSTALLDIR=/home/mine/.opam/4.02.1/lib -AR=ar -INSTALL=install -OCAMLFIND=ocamlfind -INSTMETH=findlib -OBJSUFFIX=o -HASOCAMLOPT=yes -HASDYNLINK=yes - -include project.mak diff --git a/README b/README deleted file mode 100644 index 6f934b8..0000000 --- a/README +++ /dev/null @@ -1,130 +0,0 @@ ->OVERVIEW: - -This library implements arithmetic and logical operations over -arbitrary-precision integers. - -The module is simply named "Z". Its interface is similar to that of -the Int32, Int64 and Nativeint modules from the OCaml standard -library, with some additional functions. See the file z.mlip for -documentation. - -The implementation uses GMP (the GNU Multiple Precision arithmetic -library) to compute over big integers. -However, small integers are represented as unboxed Caml integers, to save -space and improve performance. Big integers are allocated in the Caml heap, -bypassing GMP's memory management and achieving better GC behavior than e.g. -the MLGMP library. -Computations on small integers use a special, faster path (coded in assembly -for some platforms and functions) eschewing calls to GMP, while computations -on large intergers use the low-level MPN functions from GMP. - -Arbitrary-precision integers can be compared correctly using OCaml's -polymorphic comparison operators (=, <, >, etc.). -This requires OCaml version 3.12.1 or later, though. - -Additional features include: -- a module Q for rationals, built on top of Z (see q.mli) -- a compatibility layer Big_int_Z that implements the same API as Big_int, -but uses Z internally - - - -REQUIREMENTS: - -- OCaml, preferably version 3.12.1 or later. -(Earlier versions are usable but generic comparisons will misbehave.) -- Either the GMP library or the MPIR library, including development files. -- A gcc-compatible C compiler and assembler (other compilers may work). -- The Perl programming language. -- (optional) The Findlib package manager. - - -INSTALLATION: - -1) First, run the "configure" script by typing: - - ./configure - -2) It creates a Makefile, which can be invoked by: - - make - -This builds native and bytecode versions of the library. - -3) The libraries are installed by typing: - - make install - -or, if you install to a system location but are not an administrator - - sudo make install - -If Findlib is detected, it is used to install files. -Otherwise, the files are copied to a zarith subdirectory of the directory -given by `ocamlc -where`. -The libraries are named "zarith.cmxa" and "zarith.cma", and the Findlib module -is named "zarith". -Compiling and linking with the library requires passing the "-I +zarith" -option to ocamlc / ocamlopt. -The "configure" script has a few options. Use the "-help" option to get a -list and short description of each option. - -4) (optional) -HTML API documentation is built (using ocamldoc) by the additional command - - make doc - -Test programs are built by the additional command - - make tests - -(but these are not installed). - - - -LICENSE: - -This Library is distributed under the terms of the GNU Library General -Public License version 2, with a special exception allowing unconstrained -static linking. -See LICENSE file for details. - - - -AUTHORS: - -Antoine Miné, ENS Paris. -Xavier Leroy, INRIA Paris-Rocquencourt. -Pascal Cuoq, CEA LIST. - - - -COPYRIGHT: - -Copyright (c) 2010-2011 Antoine Miné, Abstraction project. -Abstraction is part of the LIENS (Laboratoire d'Informatique de l'ENS), -a joint laboratory by: -CNRS (Centre national de la recherche scientifique, France), -ENS (École normale supérieure, Paris, France), -INRIA Rocquencourt (Institut national de recherche en informatique, France). - - - -CONTENTS: - -The source files are: -* configure - configuration script -* caml_z.c - C implementation of all functions -* caml_z_*.S - asm implementation for a few functions -* z_pp.pl - script to generate z.ml[i] from z.ml[i]p -* z.ml[i]p - templates used to generate z.ml[i]p -* big_int_z.ml[i] - wrapper to provide a Big_int compatible API to Z -* q.ml[i] - rational library, pure OCaml on top of Z -* projet.mak - builds Z, Q and the tests -* tests/ - simple regression tests and benchmarks - -Note: z_pp.pl simply scans the asm file (if any) to see which functions have -an asm implementation. It then fixes the external statements in .mlp and -.mlip accordingly. -The argument to z_pp.pl is the suffix * of the caml_z_*.S to use (guessed by -configure). diff --git a/README.md b/README.md new file mode 100644 index 0000000..9388897 --- /dev/null +++ b/README.md @@ -0,0 +1,126 @@ +# The Zarith library + +## OVERVIEW + +This library implements arithmetic and logical operations over +arbitrary-precision integers. + +The module is simply named `Z`. Its interface is similar to that of +the `Int32`, `Int64` and `Nativeint` modules from the OCaml standard +library, with some additional functions. See the file `z.mlip` for +documentation. + +The implementation uses GMP (the GNU Multiple Precision arithmetic +library) to compute over big integers. +However, small integers are represented as unboxed Caml integers, to save +space and improve performance. Big integers are allocated in the Caml heap, +bypassing GMP's memory management and achieving better GC behavior than e.g. +the MLGMP library. +Computations on small integers use a special, faster path (coded in assembly +for some platforms and functions) eschewing calls to GMP, while computations +on large intergers use the low-level MPN functions from GMP. + +Arbitrary-precision integers can be compared correctly using OCaml's +polymorphic comparison operators (`=`, `<`, `>`, etc.). +This requires OCaml version 3.12.1 or later, though. + +Additional features include: +* a module `Q` for rationals, built on top of `Z` (see `q.mli`) +* a compatibility layer `Big_int_Z` that implements the same API as Big_int from the legacy `Num` library, but uses `Z` internally + +## REQUIREMENTS + +* OCaml, preferably version 3.12.1 or later. (Earlier versions are usable but generic comparisons will misbehave.) +* Either the GMP library or the MPIR library, including development files. +* GCC or Clang or a gcc-compatible C compiler and assembler (other compilers may work). +* The Perl programming language. +* The Findlib package manager (optional, recommended). + + +## INSTALLATION + +1) First, run the "configure" script by typing: +``` + ./configure +``` +The `configure` script has a few options. Use the `-help` option to get a +list and short description of each option. + +2) It creates a Makefile, which can be invoked by: +``` + make +``` +This builds native and bytecode versions of the library. + +3) The libraries are installed by typing: +``` + make install +``` +or, if you install to a system location but are not an administrator +``` + sudo make install +``` +If Findlib is detected, it is used to install files. +Otherwise, the files are copied to a `zarith/` subdirectory of the directory +given by `ocamlc -where`. + +The libraries are named `zarith.cmxa` and `zarith.cma`, and the Findlib module +is named `zarith`. + +Compiling and linking with the library requires passing the `-I +zarith` +option to `ocamlc` / `ocamlopt`, or the `-package zarith` option to `ocamlfind`. + +4) (optional, recommended) Test programs are built and run by the additional command +``` + make tests +``` +(but these are not installed). + +5) (optional) HTML API documentation is built (using `ocamldoc`) by the additional command +``` + make doc +``` + +## LICENSE + +This Library is distributed under the terms of the GNU Library General +Public License version 2, with a special exception allowing unconstrained +static linking. +See LICENSE file for details. + + +## AUTHORS + +* Antoine Miné, Université Pierre et Marie Curie, formerly ENS Paris. +* Xavier Leroy, INRIA Paris-Rocquencourt. +* Pascal Cuoq, CEA LIST. + + +## COPYRIGHT + +Copyright (c) 2010-2011 Antoine Miné, Abstraction project. +Abstraction is part of the LIENS (Laboratoire d'Informatique de l'ENS), +a joint laboratory by: +CNRS (Centre national de la recherche scientifique, France), +ENS (École normale supérieure, Paris, France), +INRIA Rocquencourt (Institut national de recherche en informatique, France). + + +## CONTENTS + +Source files | Description +--------------------|----------------------------------------- + configure | configuration script + caml_z.c | C implementation of all functions + caml_z_*.S | asm implementation for a few functions + z_pp.pl | script to generate z.ml[i] from z.ml[i]p + z.ml[i]p | templates used to generate z.ml[i]p + big_int_z.ml[i] | wrapper to provide a Big_int compatible API to Z + q.ml[i] | rational library, pure OCaml on top of Z + projet.mak | builds Z, Q and the tests + tests/ | simple regression tests and benchmarks + +Note: `z_pp.pl` simply scans the asm file (if any) to see which functions have +an asm implementation. It then fixes the external statements in .mlp and +.mlip accordingly. +The argument to `z_pp.pl` is the suffix `*` of the `caml_z_*.S` to use (guessed by configure). diff --git a/caml_z.c b/caml_z.c index b690a2a..5d258b9 100644 --- a/caml_z.c +++ b/caml_z.c @@ -521,7 +521,7 @@ CAMLprim value ml_z_of_float(value v) Z_MARK_OP; x = Double_val(v); #if Z_USE_NATINT - if (x >= Z_MIN_INT_FL && x <= Z_MAX_INT_FL) return Val_long(x); + if (x >= Z_MIN_INT_FL && x <= Z_MAX_INT_FL) return Val_long((intnat) x); #endif Z_MARK_SLOW; #ifdef ARCH_ALIGN_INT64 @@ -2713,7 +2713,7 @@ CAMLprim value ml_z_pow(value base, value exp) CAMLparam2(base,exp); CAMLlocal1(r); mpz_t mbase; - int e = Long_val(exp); + intnat e = Long_val(exp); if (e < 0) caml_invalid_argument("Z.pow: exponent must be non-negative"); ml_z_mpz_init_set_z(mbase, base); @@ -2728,7 +2728,7 @@ CAMLprim value ml_z_root(value a, value b) CAMLparam2(a,b); CAMLlocal1(r); mpz_t ma; - int mb = Long_val(b); + intnat mb = Long_val(b); if (mb < 0) caml_invalid_argument("Z.root: exponent must be non-negative"); ml_z_mpz_init_set_z(ma, a); diff --git a/project.mak b/project.mak index 79d5750..4857feb 100644 --- a/project.mak +++ b/project.mak @@ -39,10 +39,11 @@ MLISRC = z.mli q.mli big_int_Z.mli AUTOGEN = z.ml z.mli z_features.h CMIOBJ = $(MLISRC:%.mli=%.cmi) +CMXOBJ = $(MLISRC:%.mli=%.cmx) TOINSTALL := zarith.h zarith.cma libzarith.$(LIBSUFFIX) $(MLISRC) $(CMIOBJ) ifeq ($(HASOCAMLOPT),yes) -TOINSTALL := $(TOINSTALL) zarith.$(LIBSUFFIX) zarith.cmxa +TOINSTALL := $(TOINSTALL) zarith.$(LIBSUFFIX) zarith.cmxa $(CMXOBJ) endif ifeq ($(HASDYNLINK),yes) @@ -65,7 +66,7 @@ zarith.cmxa zarith.$(LIBSUFFIX): $(MLSRC:%.ml=%.cmx) $(OCAMLMKLIB) -failsafe -o zarith $+ $(LIBS) zarith.cmxs: zarith.cmxa libzarith.$(LIBSUFFIX) - $(OCAMLOPT) -shared -o $@ -I . zarith.cmxa + $(OCAMLOPT) -shared -o $@ -I . zarith.cmxa -linkall libzarith.$(LIBSUFFIX) dllzarith.$(DLLSUFFIX): $(SSRC:%.S=%.$(OBJSUFFIX)) $(CSRC:%.c=%.$(OBJSUFFIX)) $(OCAMLMKLIB) -failsafe -o zarith $+ $(LIBS) @@ -132,7 +133,7 @@ clean: make -C tests clean depend: $(AUTOGEN) - $(OCAMLDEP) -native $(OCAMLINC) *.ml *.mli > depend + $(OCAMLDEP) -native $(OCAMLINC) $(MLSRC) $(MLISRC) > depend include depend diff --git a/q.ml b/q.ml index d6e5f6c..e7dfd81 100644 --- a/q.ml +++ b/q.ml @@ -189,7 +189,41 @@ let to_int64 x = Z.to_int64 (to_bigint x) let to_nativeint x = Z.to_nativeint (to_bigint x) - +let to_float x = + match classify x with + | ZERO -> 0.0 + | INF -> infinity + | MINF -> neg_infinity + | UNDEF -> nan + | NZERO -> + let p = x.num and q = x.den in + let np = Z.numbits p and nq = Z.numbits q in + if np <= 53 && nq <= 53 then + (* p and q convert to floats exactly; use FP division to get the + correctly-rounded result. *) + Int64.to_float (Z.to_int64 p) /. Int64.to_float (Z.to_int64 q) + else begin + (* |p| is in [2^(np-1), 2^np) + q is in [2^(nq-1), 2^nq) + hence |p/q| is in (2^(np-nq-1), 2^(np-nq+1)). + We define n such that |p/q*2^n| is in [2^54, 2^56). + >= 2^54 so that the round to odd technique applies. + < 2^56 so that the integral part is representable as an int64. *) + let n = 55 - (np - nq) in + (* Scaling p/q by 2^n *) + let (p', q') = + if n >= 0 + then (Z.shift_left p n, q) + else (p, Z.shift_left q (-n)) in + (* Euclidean division of p' by q' *) + let (quo, rem) = Z.ediv_rem p' q' in + (* quo is the integral part of p/q*2^n + rem/q' is the fractional part. *) + (* Round quo to float *) + let f = Z.round_to_float quo (Z.sign rem = 0) in + (* Apply exponent *) + ldexp f (-n) + end (* operations *) (* ---------- *) diff --git a/q.mli b/q.mli index f398d37..c43ca1b 100644 --- a/q.mli +++ b/q.mli @@ -164,6 +164,11 @@ val to_nativeint: t -> nativeint val to_string: t -> string (** Converts to human-readable, decimal, [/]-separated rational. *) +val to_float: t -> float +(** Converts to a floating-point number, using the current + floating-point rounding mode. With the default rounding mode, + the result is the floating-point number closest to the given + rational; ties break to even mantissa. *) (** {1 Arithmetic operations} *) diff --git a/tests/bi.ml b/tests/bi.ml index 7d7b9ea..415d0ca 100644 --- a/tests/bi.ml +++ b/tests/bi.ml @@ -35,12 +35,16 @@ let random_int64 () = let random_int () = Int64.to_int (random_int64 ()) let random_string () = - let s = String.create (1 + Random.int 200) in - for i = 0 to String.length s - 1 do - s.[i] <- Char.chr (48 + Random.int 10) + let l = 1 + Random.int 200 in + let s = Buffer.create l in + let st = if l > 1 && Random.bool () then begin + Buffer.add_char s '-'; + 1 + end else 0 in + for i = st to l - 1 do + Buffer.add_char s (Char.chr (48 + Random.int 10)) done; - if String.length s > 1 && Random.bool () then s.[0] <- '-'; - s + Buffer.contents s (* list utility *) diff --git a/tests/tofloat.ml b/tests/tofloat.ml index 291c50d..511daa1 100644 --- a/tests/tofloat.ml +++ b/tests/tofloat.ml @@ -25,6 +25,14 @@ let test1 (mant: int64) (exp: int) = false end +let rnd64 () = + let m1 = Random.bits() in (* 30 bits *) + let m2 = Random.bits() in (* 30 bits *) + let m3 = Random.bits() in + Int64.(logor (of_int m1) + (logor (shift_left (of_int m2) 30) + (shift_left (of_int m3) 60))) + let testN numrounds = printf " (%d tests)... %!" numrounds; let errors = ref 0 in @@ -36,12 +44,7 @@ let testN numrounds = done; (* Some random int64 values scaled by some random power of 2 *) for i = 1 to numrounds do - let m1 = Random.bits() in (* 30 bits *) - let m2 = Random.bits() in (* 30 bits *) - let m3 = Random.bits() in - let m = Int64.(logor (of_int m1) - (logor (shift_left (of_int m2) 30) - (shift_left (of_int m3) 60))) in + let m = rnd64() in let exp = Random.int 1100 in (* sometimes +inf will result *) if not (test1 m exp) then incr errors done; @@ -55,38 +58,77 @@ let testN numrounds = then printf "passed\n%!" else printf "FAILED (%d errors)\n%!" !errors +let testQ1 (mant1: int64) (exp1: int) (mant2: int64) (exp2: int) = + let expected = + ldexp (Int64.to_float mant1) exp1 /. ldexp (Int64.to_float mant2) exp2 in + let actual = + Q.to_float (Q.make (Z.shift_left (Z.of_int64 mant1) exp1) + (Z.shift_left (Z.of_int64 mant2) exp2)) in + if compare actual expected = 0 then true else begin + printf "%Ld * 2^%d / %Ld * 2^%d : expected %s, got %s\n" + mant1 exp1 mant2 exp2 (hex_of_float expected) (hex_of_float actual); + false + end + +let testQN numrounds = + printf " (%d tests)... %!" numrounds; + let errors = ref 0 in + (* Some special values *) + if not (testQ1 0L 0 1L 0) then incr errors; + if not (testQ1 1L 0 0L 0) then incr errors; + if not (testQ1 (-1L) 0 0L 0) then incr errors; + if not (testQ1 0L 0 0L 0) then incr errors; + (* Some random fractions *) + for i = 1 to numrounds do + let m1 = Random.int64 0x20000000000000L in + let m1 = if Random.bool() then m1 else Int64.neg m1 in + let exp1 = Random.int 500 in + let m2 = Random.int64 0x20000000000000L in + let exp2 = Random.int 500 in + if not (testQ1 m1 exp1 m2 exp2) then incr errors + done; + if !errors = 0 + then printf "passed\n%!" + else printf "FAILED (%d errors)\n%!" !errors + let _ = let numrounds = if Array.length Sys.argv >= 2 then int_of_string Sys.argv.(1) else 100_000 in - printf "Default rounding mode"; + printf "Default rounding mode (Z)"; testN numrounds; + printf "Default rounding mode (Q)"; + testQN numrounds; if setround FE_TOWARDZERO then begin - printf "Round toward zero"; - testN numrounds + printf "Round toward zero (Z)"; + testN numrounds; + printf "Round toward zero (Q)"; + testQN numrounds end else begin printf "Round toward zero not supported, skipping\n" end; if setround FE_DOWNWARD then begin - printf "Round downward"; - testN numrounds + printf "Round downward (Z)"; + testN numrounds; + printf "Round downward (Q)"; + testQN numrounds end else begin printf "Round downward not supported, skipping\n" end; if setround FE_UPWARD then begin - printf "Round upward"; - testN numrounds + printf "Round upward (Z)"; + testN numrounds; + printf "Round upward (Q)"; + testQN numrounds end else begin printf "Round upward not supported, skipping\n" end; if setround FE_TONEAREST then begin - printf "Round to nearest"; - testN numrounds + printf "Round to nearest (Z)"; + testN numrounds; + printf "Round to nearest (Q)"; + testQN numrounds end else begin printf "Round to nearest not supported, skipping\n" end - - - - diff --git a/z.mlip b/z.mlip index 9cf13f8..fdddc7f 100644 --- a/z.mlip +++ b/z.mlip @@ -60,7 +60,7 @@ val one: t val minus_one: t (** The number -1. *) -external of_int: int -> t = "ml_z_of_int" "noalloc" +external of_int: int -> t = "ml_z_of_int" @NOALLOC (** Converts from a base integer. *) external of_int32: int32 -> t = "ml_z_of_int32" @@ -74,7 +74,7 @@ external of_nativeint: nativeint -> t = "ml_z_of_nativeint" external of_float: float -> t = "ml_z_of_float" (** Converts from a floating-point value. - The value is truncated. + The value is truncated (rounded towards zero). Raises [Overflow] on infinity and NaN arguments. *) @@ -87,6 +87,8 @@ val of_string: string -> t represented, in hexadecimal, octal, or binary, respectively. Otherwise, base 10 is assumed. (Unlike C, a lone [0] prefix does not denote octal.) + Raises an [Invalid_argument] exception if the string is not a + syntactically correct representation of an integer. *) val of_substring : string -> pos:int -> len:int -> t @@ -226,14 +228,14 @@ external shift_right_trunc: t -> int -> t = shift_right_trunc@ASM The second argument must be non-negative. *) -external numbits: t -> int = "ml_z_numbits" "noalloc" +external numbits: t -> int = "ml_z_numbits" @NOALLOC (** Returns the number of significant bits in the given number. If [x] is zero, [numbits x] returns 0. Otherwise, [numbits x] returns a positive integer [n] such that [2^{n-1} <= |x| < 2^n]. Note that [numbits] is defined for negative arguments, and that [numbits (-x) = numbits x]. *) -external trailing_zeros: t -> int = "ml_z_trailing_zeros" "noalloc" +external trailing_zeros: t -> int = "ml_z_trailing_zeros" @NOALLOC (** Returns the number of trailing 0 bits in the given number. If [x] is zero, [trailing_zeros x] returns [max_int]. Otherwise, [trailing_zeros x] returns a nonnegative integer [n] @@ -266,16 +268,16 @@ external hamdist: t -> t -> int = "ml_z_hamdist" *) external to_int: t -> int = "ml_z_to_int" -(** Converts to a base integer. May raise an [Overflow]. *) +(** Converts to a base integer. May raise [Overflow]. *) external to_int32: t -> int32 = "ml_z_to_int32" -(** Converts to a 32-bit integer. May raise an [Overflow]. *) +(** Converts to a 32-bit integer. May raise [Overflow]. *) external to_int64: t -> int64 = "ml_z_to_int64" (** Converts to a 64-bit integer. May raise [Overflow]. *) external to_nativeint: t -> nativeint = "ml_z_to_nativeint" -(** Converts to a native integer. May raise an [Overflow]. *) +(** Converts to a native integer. May raise [Overflow]. *) val to_float: t -> float (** Converts to a floating-point value. @@ -315,16 +317,16 @@ external format: string -> t -> string = "ml_z_format" are simply ignored (and not copied in the output). *) -external fits_int: t -> bool = "ml_z_fits_int" "noalloc" +external fits_int: t -> bool = "ml_z_fits_int" @NOALLOC (** Whether the argument fits in a regular [int]. *) -external fits_int32: t -> bool = "ml_z_fits_int32" "noalloc" +external fits_int32: t -> bool = "ml_z_fits_int32" @NOALLOC (** Whether the argument fits in an [int32]. *) -external fits_int64: t -> bool = "ml_z_fits_int64" "noalloc" +external fits_int64: t -> bool = "ml_z_fits_int64" @NOALLOC (** Whether the argument fits in an [int64]. *) -external fits_nativeint: t -> bool = "ml_z_fits_nativeint" "noalloc" +external fits_nativeint: t -> bool = "ml_z_fits_nativeint" @NOALLOC (** Whether the argument fits in a [nativeint]. *) @@ -353,7 +355,7 @@ val pp_print: Format.formatter -> t -> unit (** {1 Ordering} *) -external compare: t -> t -> int = "ml_z_compare" "noalloc" +external compare: t -> t -> int = "ml_z_compare" @NOALLOC (** Comparison. [compare x y] returns 0 if [x] equals [y], -1 if [x] is smaller than [y], and 1 if [x] is greater than [y]. @@ -361,7 +363,7 @@ external compare: t -> t -> int = "ml_z_compare" "noalloc" only on OCaml 3.12.1 and later versions. *) -external equal: t -> t -> bool = "ml_z_equal" "noalloc" +external equal: t -> t -> bool = "ml_z_equal" @NOALLOC (** Equality test. *) val leq: t -> t -> bool @@ -376,7 +378,7 @@ val lt: t -> t -> bool val gt: t -> t -> bool (** Greater than (and not equal). *) -external sign: t -> int = "ml_z_sign" "noalloc" +external sign: t -> int = "ml_z_sign" @NOALLOC (** Returns -1, 0, or 1 when the argument is respectively negative, null, or positive. *) @@ -393,7 +395,7 @@ val is_even: t -> bool val is_odd: t -> bool (** Returns true if the argument is odd, false if even. *) -external hash: t -> int = "ml_z_hash" "noalloc" +external hash: t -> int = "ml_z_hash" @NOALLOC (** Hashes a number. This functions gives the same result as OCaml's polymorphic hashing function. @@ -410,10 +412,12 @@ external gcd: t -> t -> t = "ml_z_gcd" *) val gcdext: t -> t -> (t * t * t) -(** [gcd_ext u v] returns [(g,s,t)] where [g] is the greatest common divisor +(** [gcdext u v] returns [(g,s,t)] where [g] is the greatest common divisor and [g=us+vt]. - [g] is always positive. + [g] is always positive. Raises a [Division_by_zero] is either argument is null. + + Note: the function is based on the GMP [mpn_gcdext] function. The exact choice of [s] and [t] such that [g=us+vt] is not specified, as it may vary from a version of GMP to another (it has changed notably in GMP 4.3.0 and 4.3.1). *) val lcm: t -> t -> t @@ -469,7 +473,8 @@ external pow: t -> int -> t = "ml_z_pow" *) external sqrt: t -> t = "ml_z_sqrt" -(** Returns the square root. The result is truncated. +(** Returns the square root. The result is truncated (rounded down + to an integer). Raises an [Invalid_argument] on negative arguments. *) @@ -503,7 +508,7 @@ val log2up: t -> int (** {1 Representation} *) -external size: t -> int = "ml_z_size" "noalloc" +external size: t -> int = "ml_z_size" @NOALLOC (** Returns the number of machine words used to represent the number. *) external extract: t -> int -> int -> t = "ml_z_extract" @@ -517,7 +522,7 @@ val signed_extract: t -> int -> int -> t (** [signed_extract a off len] extracts bits [off] to [off]+[len]-1 of [b], as [extract] does, then sign-extends bit [len-1] of the result (that is, bit [off + len - 1] of [a]). The result is between - [- 2{^[len]-1}] (included) and [2{^[len]-1}] excluded, + [- 2{^[len]-1}] (included) and [2{^[len]-1}] (excluded), and equal to [extract a off len] modulo [2{^len}]. *) @@ -598,7 +603,7 @@ external (lsl): t -> int -> t = shift_left@ASM external (asr): t -> int -> t = shift_right@ASM (** Bit-wise shift to the right [shift_right]. *) -external (~$): int -> t = "ml_z_of_int" "noalloc" +external (~$): int -> t = "ml_z_of_int" @NOALLOC (** Conversion from [int] [of_int]. *) external ( ** ): t -> int -> t = "ml_z_pow" @@ -608,3 +613,8 @@ external ( ** ): t -> int -> t = "ml_z_pow" val version: string (** Library version (this file refers to version [@VERSION]). *) + +(**/**) + +(** For internal use in module [Q]. *) +val round_to_float: t -> bool -> float diff --git a/z.mlp b/z.mlp index ee7b8f5..58763de 100644 --- a/z.mlp +++ b/z.mlp @@ -47,7 +47,7 @@ external lognot: t -> t = lognot@ASM external shift_left: t -> int -> t = shift_left@ASM external shift_right: t -> int -> t = shift_right@ASM external shift_right_trunc: t -> int -> t = shift_right_trunc@ASM -external of_int: int -> t = "ml_z_of_int" "noalloc" +external of_int: int -> t = "ml_z_of_int" @NOALLOC external of_int32: int32 -> t = "ml_z_of_int32" external of_int64: int64 -> t = "ml_z_of_int64" external of_nativeint: nativeint -> t = "ml_z_of_nativeint" @@ -58,22 +58,22 @@ external to_int64: t -> int64 = "ml_z_to_int64" external to_nativeint: t -> nativeint = "ml_z_to_nativeint" external format: string -> t -> string = "ml_z_format" external of_substring_base: int -> string -> pos:int -> len:int -> t = "ml_z_of_substring_base" -external compare: t -> t -> int = "ml_z_compare" "noalloc" -external equal: t -> t -> bool = "ml_z_equal" "noalloc" -external sign: t -> int = "ml_z_sign" "noalloc" +external compare: t -> t -> int = "ml_z_compare" @NOALLOC +external equal: t -> t -> bool = "ml_z_equal" @NOALLOC +external sign: t -> int = "ml_z_sign" @NOALLOC external gcd: t -> t -> t = "ml_z_gcd" external gcdext_intern: t -> t -> (t * t * bool) = "ml_z_gcdext_intern" external sqrt: t -> t = "ml_z_sqrt" external sqrt_rem: t -> (t * t) = "ml_z_sqrt_rem" -external numbits: t -> int = "ml_z_numbits" "noalloc" -external trailing_zeros: t -> int = "ml_z_trailing_zeros" "noalloc" +external numbits: t -> int = "ml_z_numbits" @NOALLOC +external trailing_zeros: t -> int = "ml_z_trailing_zeros" @NOALLOC external popcount: t -> int = "ml_z_popcount" external hamdist: t -> t -> int = "ml_z_hamdist" -external size: t -> int = "ml_z_size" "noalloc" -external fits_int: t -> bool = "ml_z_fits_int" "noalloc" -external fits_int32: t -> bool = "ml_z_fits_int32" "noalloc" -external fits_int64: t -> bool = "ml_z_fits_int64" "noalloc" -external fits_nativeint: t -> bool = "ml_z_fits_nativeint" "noalloc" +external size: t -> int = "ml_z_size" @NOALLOC +external fits_int: t -> bool = "ml_z_fits_int" @NOALLOC +external fits_int32: t -> bool = "ml_z_fits_int32" @NOALLOC +external fits_int64: t -> bool = "ml_z_fits_int64" @NOALLOC +external fits_nativeint: t -> bool = "ml_z_fits_nativeint" @NOALLOC external extract: t -> int -> int -> t = "ml_z_extract" external powm: t -> t -> t -> t = "ml_z_powm" external pow: t -> int -> t = "ml_z_pow" @@ -85,7 +85,7 @@ external perfect_power: t -> bool = "ml_z_perfect_power" external perfect_square: t -> bool = "ml_z_perfect_square" external probab_prime: t -> int -> int = "ml_z_probab_prime" external nextprime: t -> t = "ml_z_nextprime" -external hash: t -> int = "ml_z_hash" "noalloc" +external hash: t -> int = "ml_z_hash" @NOALLOC external to_bits: t -> string = "ml_z_to_bits" external of_bits: string -> t = "ml_z_of_bits" @@ -108,7 +108,7 @@ let of_substring = of_substring_base 0 let of_string_base base s = of_substring_base base s ~pos:0 ~len:(String.length s) let ediv_rem a b = - (* we have a = a * b + r, but [Big_int]'s remainder satisfies 0 <= r < |b|, + (* we have a = q * b + r, but [Big_int]'s remainder satisfies 0 <= r < |b|, while [Z]'s remainder satisfies -|b| < r < |b| and sign(r) = sign(a) *) let q,r = div_rem a b in @@ -132,7 +132,7 @@ let lcm u v = let g = gcd u v in abs (mul (divexact u g) v) -external testbit_internal: t -> int -> bool = "ml_z_testbit" "noalloc" +external testbit_internal: t -> int -> bool = "ml_z_testbit" @NOALLOC let testbit x n = if n >= 0 then testbit_internal x n else invalid_arg "Z.testbit" (* The test [n >= 0] is done in Caml rather than in the C stub code @@ -213,7 +213,7 @@ external (lxor): t -> t -> t = logxor@ASM external (~!): t -> t = lognot@ASM external (lsl): t -> int -> t = shift_left@ASM external (asr): t -> int -> t = shift_right@ASM -external (~$): int -> t = "ml_z_of_int" "noalloc" +external (~$): int -> t = "ml_z_of_int" @NOALLOC external ( ** ): t -> int -> t = "ml_z_pow" let version = @VERSION diff --git a/z_pp.pl b/z_pp.pl index ff10581..48a163a 100755 --- a/z_pp.pl +++ b/z_pp.pl @@ -25,6 +25,13 @@ die "Usage: './z_pp.pl architecture'" unless $#ARGV==0; $v = `grep version META`; ($ver) = $v =~ /version\s*=\s*(\S+)/; +$ov = `ocamlc -version`; +($major,$minor,$extra) = split(/\./, $ov, 3); +if ($major > 4 || ($major == 4 && $minor >= 3)) { + $noalloc = "[\@\@noalloc]"; +} else { + $noalloc = "\"noalloc\""; +} # scan assembly @@ -64,6 +71,7 @@ sub doml { $l =~ s/$f\@ASM/$r/g; } $l =~ s/\@VERSION/$ver/; + $l =~ s/\@NOALLOC/$noalloc/; print O "$l"; } close F; -- Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-ocaml-maint/packages/ocaml-zarith.git _______________________________________________ Pkg-ocaml-maint-commits mailing list Pkg-ocaml-maint-commits@lists.alioth.debian.org http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-ocaml-maint-commits