This commit is contained in:
parent
aa2ff7b2f0
commit
2f3113f55d
11742 changed files with 1223940 additions and 0 deletions
574
unikernel/duniverse/Zarith/q.ml
Normal file
574
unikernel/duniverse/Zarith/q.ml
Normal file
|
|
@ -0,0 +1,574 @@
|
|||
(**
|
||||
Rationals.
|
||||
|
||||
|
||||
This file is part of the Zarith library
|
||||
http://forge.ocamlcore.org/projects/zarith .
|
||||
It is distributed under LGPL 2 licensing, with static linking exception.
|
||||
See the LICENSE file included in the distribution.
|
||||
|
||||
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).
|
||||
|
||||
*)
|
||||
|
||||
type t = {
|
||||
num: Z.t; (** Numerator. *)
|
||||
den: Z.t; (** Denominator, >= 0 *)
|
||||
}
|
||||
(* Type of rationals.
|
||||
Invariants:
|
||||
- den is always >= 0;
|
||||
- num and den have no common factor;
|
||||
- if den=0, then num is -1, 0 or 1.
|
||||
- if num=0, then den is -1, 0 or 1.
|
||||
*)
|
||||
|
||||
|
||||
|
||||
(* creation *)
|
||||
(* -------- *)
|
||||
|
||||
(* make *)
|
||||
let mk n d =
|
||||
{ num = n; den = d; }
|
||||
|
||||
(* make and normalize n/d, assuming d > 0 *)
|
||||
let make_real n d =
|
||||
if n == Z.zero || d == Z.one then mk n Z.one
|
||||
else
|
||||
let g = Z.gcd n d in
|
||||
if g == Z.one
|
||||
then mk n d
|
||||
else mk (Z.divexact n g) (Z.divexact d g)
|
||||
|
||||
(* make and normalize any fraction *)
|
||||
let make n d =
|
||||
let sd = Z.sign d in
|
||||
if sd = 0 then mk (Z.of_int (Z.sign n)) Z.zero else
|
||||
if sd > 0 then make_real n d else
|
||||
make_real (Z.neg n) (Z.neg d)
|
||||
|
||||
let of_bigint n = mk n Z.one
|
||||
(* n/1 *)
|
||||
|
||||
let of_int n = of_bigint (Z.of_int n)
|
||||
|
||||
let of_int32 n = of_bigint (Z.of_int32 n)
|
||||
|
||||
let of_int64 n = of_bigint (Z.of_int64 n)
|
||||
|
||||
let of_nativeint n = of_bigint (Z.of_nativeint n)
|
||||
|
||||
let of_ints n d = make (Z.of_int n) (Z.of_int d)
|
||||
|
||||
let zero = of_bigint Z.zero
|
||||
(* 0/1 *)
|
||||
|
||||
let one = of_bigint Z.one
|
||||
(* 1/1 *)
|
||||
|
||||
let minus_one = of_bigint Z.minus_one
|
||||
(* -1/1 *)
|
||||
|
||||
let inf = mk Z.one Z.zero
|
||||
(* 1/0 *)
|
||||
|
||||
let minus_inf = mk Z.minus_one Z.zero
|
||||
(* -1/0 *)
|
||||
|
||||
let undef = mk Z.zero Z.zero
|
||||
(* 0/0 *)
|
||||
|
||||
let of_float d =
|
||||
if d = infinity then inf else
|
||||
if d = neg_infinity then minus_inf else
|
||||
if classify_float d = FP_nan then undef else
|
||||
let m,e = frexp d in
|
||||
(* put into the form m * 2^e, where m is an integer *)
|
||||
let m,e = Z.of_float (ldexp m 53), e-53 in
|
||||
if e >= 0 then of_bigint (Z.shift_left m e)
|
||||
else make_real m (Z.shift_left Z.one (-e))
|
||||
|
||||
(* queries *)
|
||||
(* ------- *)
|
||||
|
||||
type kind =
|
||||
| ZERO (* 0 *)
|
||||
| INF (* 1/0 *)
|
||||
| MINF (* -1/0 *)
|
||||
| UNDEF (* 0/0 *)
|
||||
| NZERO (* non-special, non-0 *)
|
||||
|
||||
let classify n =
|
||||
if n.den == Z.zero then
|
||||
match Z.sign n.num with
|
||||
| 1 -> INF
|
||||
| -1 -> MINF
|
||||
| _ -> UNDEF
|
||||
else
|
||||
if n.num == Z.zero
|
||||
then ZERO
|
||||
else NZERO
|
||||
|
||||
let is_real n = (n.den != Z.zero)
|
||||
|
||||
let num x = x.num
|
||||
|
||||
let den x = x.den
|
||||
|
||||
let sign x = Z.sign x.num
|
||||
(* sign undef = 0
|
||||
sign inf = 1
|
||||
sign -inf = -1
|
||||
*)
|
||||
|
||||
let equal x y =
|
||||
(Z.equal x.num y.num) && (Z.equal x.den y.den) && (classify x <> UNDEF)
|
||||
|
||||
let compare x y =
|
||||
match classify x, classify y with
|
||||
| UNDEF,UNDEF | INF,INF | MINF,MINF -> 0
|
||||
| UNDEF,_ -> -1
|
||||
| _,UNDEF -> 1
|
||||
| MINF,_ | _,INF -> -1
|
||||
| INF,_ | _,MINF -> 1
|
||||
| _ ->
|
||||
if x.den = y.den (* implies equality,
|
||||
especially if immediate value and not a pointer,
|
||||
in particular in the case den = 1 *)
|
||||
then Z.compare x.num y.num
|
||||
else
|
||||
Z.compare
|
||||
(Z.mul x.num y.den)
|
||||
(Z.mul y.num x.den)
|
||||
|
||||
let min a b = if compare a b <= 0 then a else b
|
||||
let max a b = if compare a b >= 0 then a else b
|
||||
|
||||
|
||||
let leq x y =
|
||||
match classify x, classify y with
|
||||
| UNDEF,_ | _,UNDEF -> false
|
||||
| MINF,_ | _,INF -> true
|
||||
| INF,_ | _,MINF -> false
|
||||
| _ ->
|
||||
if x.den = y.den
|
||||
then Z.leq x.num y.num
|
||||
else
|
||||
Z.leq
|
||||
(Z.mul x.num y.den)
|
||||
(Z.mul y.num x.den)
|
||||
|
||||
let lt x y =
|
||||
match classify x, classify y with
|
||||
| UNDEF,_ | _,UNDEF -> false
|
||||
| INF,_ | _,MINF -> false
|
||||
| MINF,_ | _,INF -> true
|
||||
| _ ->
|
||||
if x.den = y.den
|
||||
then Z.lt x.num y.num
|
||||
else
|
||||
Z.lt
|
||||
(Z.mul x.num y.den)
|
||||
(Z.mul y.num x.den)
|
||||
|
||||
let geq x y = leq y x
|
||||
let gt x y = lt y x
|
||||
|
||||
let to_string n =
|
||||
match classify n with
|
||||
| UNDEF -> "undef"
|
||||
| INF -> "+inf"
|
||||
| MINF -> "-inf"
|
||||
| ZERO -> "0"
|
||||
| NZERO ->
|
||||
if Z.equal n.den Z.one then Z.to_string n.num
|
||||
else (Z.to_string n.num) ^ "/" ^ (Z.to_string n.den)
|
||||
|
||||
let to_bigint x = Z.div x.num x.den
|
||||
(* raises a Division by zero in case x is undefined or infinity *)
|
||||
|
||||
let to_int x = Z.to_int (to_bigint x)
|
||||
|
||||
let to_int32 x = Z.to_int32 (to_bigint x)
|
||||
|
||||
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
|
||||
let negat =
|
||||
if Z.sign p < 0 then -1 else 1
|
||||
in
|
||||
(* p is in [2^(np-1), 2^np)
|
||||
q is in [2^(nq-1), 2^nq)
|
||||
We define n,p',q' such that p'/q'*2^n=p/q and |p'/q'| is in [1, 2). *)
|
||||
let n = np - nq in
|
||||
(* Scaling p/q by 2^n *)
|
||||
let (p', q') =
|
||||
if n >= 0
|
||||
then (p, Z.shift_left q n)
|
||||
else (Z.shift_left p (-n), q)
|
||||
in
|
||||
let (p', n) =
|
||||
if Z.geq (Z.abs p') q'
|
||||
then (p', n)
|
||||
else (Z.shift_left p' 1, pred n)
|
||||
in
|
||||
(* If we divided p' by q' now, the resulting quotient would
|
||||
have one significant digit. *)
|
||||
let p' = Z.shift_left p' 54 in
|
||||
(* When we divide p' by q' next, the resulting quotient will
|
||||
have 55 significant digits. The strategy is:
|
||||
- First, compute the quotient with 55 significant digits in
|
||||
round-to-odd, and
|
||||
- Second, round that number to the number of effective
|
||||
significant digits we desire for the result, which is 53
|
||||
for a normal result and less than 53 for a subnormal result.
|
||||
We cannot afford an intermediate rounding at 53 significant digits
|
||||
if the end-result is subnormal. See
|
||||
https://github.com/ocaml/Zarith/issues/29 *)
|
||||
(* Euclidean division of p' by q' *)
|
||||
let (quo, rem) = Z.ediv_rem p' q' in
|
||||
if n <= -1080
|
||||
then
|
||||
(* The end result is +0.0 or -0.0 (depending on negat)
|
||||
or perhaps the next floating-point number of the same
|
||||
sign (depending on the current rounding mode. *)
|
||||
ldexp (float_of_int negat) (-1080)
|
||||
else
|
||||
let offset =
|
||||
if n <= -1023
|
||||
then
|
||||
(* The end result will be subnormal, add an offset
|
||||
to make the rounding happen directly at the place
|
||||
where it should happend.
|
||||
quo has the form: 1xxxx...
|
||||
we add: 1000000...
|
||||
so as to end up with: 101xxxx... *)
|
||||
Z.shift_left (Z.of_int negat) (55 + (-1023 - n))
|
||||
else
|
||||
Z.zero
|
||||
in
|
||||
let quo = Z.add offset quo in
|
||||
let quo =
|
||||
if Z.sign rem = 0
|
||||
then quo
|
||||
else Z.logor Z.one quo (* round to odd *)
|
||||
in
|
||||
(* The FPU rounding mode affects the Z.to_float that comes next,
|
||||
making the rounding computed according to the current FPU rounding
|
||||
mode. *)
|
||||
let f = Z.to_float quo in
|
||||
(* The subtraction that comes next is exact, so that the rounding
|
||||
mode does not change what it does. *)
|
||||
let f = f -. (Z.to_float offset)
|
||||
in
|
||||
(* ldexp is also exact and unaffected by the rounding mode.
|
||||
We have made sure that if the end result is going to be subnormal,
|
||||
then f has exactly the correct number of significant digits for
|
||||
no rounding to happen here. *)
|
||||
ldexp f (n - 54)
|
||||
end
|
||||
|
||||
(* operations *)
|
||||
(* ---------- *)
|
||||
|
||||
let neg x =
|
||||
mk (Z.neg x.num) x.den
|
||||
(* neg undef = undef
|
||||
neg inf = -inf
|
||||
neg -inf = inf
|
||||
*)
|
||||
|
||||
let abs x =
|
||||
mk (Z.abs x.num) x.den
|
||||
(* abs undef = undef
|
||||
abs inf = abs -inf = inf
|
||||
*)
|
||||
|
||||
(* addition or substraction (zaors) of finite numbers *)
|
||||
let aors zaors x y =
|
||||
if x.den == y.den then (* implies equality,
|
||||
especially if immediate value and not a pointer,
|
||||
in particular in the case den = 1 *)
|
||||
make_real (zaors x.num y.num) x.den
|
||||
else
|
||||
make_real
|
||||
(zaors
|
||||
(Z.mul x.num y.den)
|
||||
(Z.mul y.num x.den))
|
||||
(Z.mul x.den y.den)
|
||||
|
||||
let add x y =
|
||||
if x.den == Z.zero || y.den == Z.zero then match classify x, classify y with
|
||||
| ZERO,_ -> y
|
||||
| _,ZERO -> x
|
||||
| UNDEF,_ | _,UNDEF -> undef
|
||||
| INF,MINF | MINF,INF -> undef
|
||||
| INF,_ | _,INF -> inf
|
||||
| MINF,_ | _,MINF -> minus_inf
|
||||
| NZERO,NZERO -> failwith "impossible case"
|
||||
else
|
||||
aors Z.add x y
|
||||
(* undef + x = x + undef = undef
|
||||
inf + -inf = -inf + inf = undef
|
||||
inf + x = x + inf = inf
|
||||
-inf + x = x + -inf = -inf
|
||||
*)
|
||||
|
||||
let sub x y =
|
||||
if x.den == Z.zero || y.den == Z.zero then match classify x, classify y with
|
||||
| ZERO,_ -> neg y
|
||||
| _,ZERO -> x
|
||||
| UNDEF,_ | _,UNDEF -> undef
|
||||
| INF,INF | MINF,MINF -> undef
|
||||
| INF,_ | _,MINF -> inf
|
||||
| MINF,_ | _,INF -> minus_inf
|
||||
| NZERO,NZERO -> failwith "impossible case"
|
||||
else
|
||||
aors Z.sub x y
|
||||
(* sub x y = add x (neg y) *)
|
||||
|
||||
let mul x y =
|
||||
if x.den == Z.zero || y.den == Z.zero then
|
||||
mk
|
||||
(Z.of_int ((Z.sign x.num) * (Z.sign y.num)))
|
||||
Z.zero
|
||||
else
|
||||
make_real (Z.mul x.num y.num) (Z.mul x.den y.den)
|
||||
|
||||
(* undef * x = x * undef = undef
|
||||
0 * inf = inf * 0 = 0 * -inf = -inf * 0 = undef
|
||||
inf * x = x * inf = sign x * inf
|
||||
-inf * x = x * -inf = - sign x * inf
|
||||
*)
|
||||
|
||||
let inv x =
|
||||
match Z.sign x.num with
|
||||
| 1 -> mk x.den x.num
|
||||
| -1 -> mk (Z.neg x.den) (Z.neg x.num)
|
||||
| _ -> if x.den == Z.zero then undef else inf
|
||||
(* 1 / undef = undef
|
||||
1 / inf = 1 / -inf = 0
|
||||
1 / 0 = inf
|
||||
|
||||
note that: inv (inv -inf) = inf <> -inf
|
||||
*)
|
||||
|
||||
let div x y =
|
||||
if Z.sign y.num >= 0
|
||||
then mul x (mk y.den y.num)
|
||||
else mul x (mk (Z.neg y.den) (Z.neg y.num))
|
||||
(* undef / x = x / undef = undef
|
||||
0 / 0 = undef
|
||||
inf / inf = inf / -inf = -inf / inf = -inf / -inf = undef
|
||||
0 / inf = 0 / -inf = x / inf = x / -inf = 0
|
||||
inf / x = sign x * inf
|
||||
-inf / x = - sign x * inf
|
||||
inf / 0 = inf
|
||||
-inf / 0 = -inf
|
||||
x / 0 = sign x * inf
|
||||
|
||||
we have div x y = mul x (inv y)
|
||||
*)
|
||||
|
||||
let mul_2exp x n =
|
||||
if x.den == Z.zero then x
|
||||
else make_real (Z.shift_left x.num n) x.den
|
||||
|
||||
let div_2exp x n =
|
||||
if x.den == Z.zero then x
|
||||
else make_real x.num (Z.shift_left x.den n)
|
||||
|
||||
|
||||
type supported_base =
|
||||
| B2 | B8 | B10 | B16
|
||||
|
||||
let int_of_base = function
|
||||
| B2 -> 2
|
||||
| B8 -> 8
|
||||
| B10 -> 10
|
||||
| B16 -> 16
|
||||
|
||||
(* [find_in_string s ~pos ~last pred] find the first index in the string between [pos]
|
||||
(inclusive) and [last] (exclusive) that satisfy the predicate [pred] *)
|
||||
let rec find_in_string s ~pos ~last p =
|
||||
if pos >= last
|
||||
then None
|
||||
else if p s.[pos]
|
||||
then Some pos
|
||||
else find_in_string s ~pos:(pos + 1) ~last p
|
||||
|
||||
(* The current implementation supports plain decimals, decimal points,
|
||||
scientific notation ('e' or 'E' for base 10 litteral and 'p' or 'P'
|
||||
for base 16), and fraction of integers (eg. 1/2). In particular it
|
||||
accepts any numeric literal accepted by OCaml's lexer.
|
||||
Restrictions:
|
||||
- exponents in scientific notation should fit on an integer
|
||||
- scientific notation only available in hexa and decimal (as in OCaml) *)
|
||||
let of_string =
|
||||
(* return a boolean (true for negative) and the next offset to read *)
|
||||
let parse_sign s i j =
|
||||
if j < i + 1
|
||||
then false, i
|
||||
else
|
||||
match s.[i] with
|
||||
| '-' -> true , i + 1
|
||||
| '+' -> false, i + 1
|
||||
| _ -> false ,i
|
||||
in
|
||||
(* return the base and the next offset to read *)
|
||||
let parse_base s i j =
|
||||
if j < i + 2
|
||||
then B10, i
|
||||
else
|
||||
match s.[i],s.[i+1] with
|
||||
| '0',('x'|'X') -> B16, i + 2
|
||||
| '0',('o'|'O') -> B8, i + 2
|
||||
| '0',('b'|'B') -> B2, i + 2
|
||||
| _ -> B10, i
|
||||
in
|
||||
let find_exponent_mark = function
|
||||
| B10 -> (function 'e' | 'E' -> true | _ -> false)
|
||||
| B16 -> (function 'p' | 'P' -> true | _ -> false)
|
||||
| B8 | B2 -> (fun _ -> false)
|
||||
in
|
||||
let of_scientific_notation s =
|
||||
let i = 0 in
|
||||
let j = String.length s in
|
||||
let sign,i = parse_sign s i j in
|
||||
let base,i = parse_base s i j in
|
||||
(* shift left due to the exponent *)
|
||||
let shift_left, j =
|
||||
match find_in_string s ~pos:i ~last:j (find_exponent_mark base) with
|
||||
| None -> 0, j
|
||||
| Some ei ->
|
||||
let pos = ei + 1 in
|
||||
let ez = Z.of_substring_base 10 s ~pos ~len:(j - pos) in
|
||||
Z.to_int ez, ei
|
||||
in
|
||||
(* shift right due to the radix *)
|
||||
let z, shift_right =
|
||||
match base with
|
||||
| B2 | B8 -> Z.of_substring_base (int_of_base base) s ~pos:i ~len:(j - i), 0
|
||||
| B10 | B16 ->
|
||||
match find_in_string s ~pos:i ~last:j ((=) '.') with
|
||||
| None -> Z.of_substring_base (int_of_base base) s ~pos:i ~len:(j - i), 0
|
||||
| Some k ->
|
||||
(* shift_right_factor correspond to the shift to apply when we move the decimal
|
||||
point one position to the left.
|
||||
|
||||
0x1.1p1 = 0x11p-3 = 0x0.11p5
|
||||
1.1e1 = 11e0 = 0.11e2 *)
|
||||
let shift_right_factor =
|
||||
match base with
|
||||
| B10 -> 1
|
||||
| B16 -> 4
|
||||
| B2 | B8 -> assert false
|
||||
in
|
||||
(* We should only consider actual digits to perform the shift. *)
|
||||
let num_digits = ref 0 in
|
||||
for h = k + 1 to j - 1 do
|
||||
match s.[h] with
|
||||
| '0' .. '9' | 'A' .. 'F' | 'a' .. 'f' ->
|
||||
incr num_digits
|
||||
| '_' -> ()
|
||||
| _ ->
|
||||
(* '-' and '+' could wrongly be accepted by Z.of_string_base *)
|
||||
invalid_arg "Q.of_string: invalid digit"
|
||||
done;
|
||||
let first_digit_after_dot =
|
||||
match find_in_string s ~pos:(k+1) ~last:j ((<>) '_') with
|
||||
| None -> j
|
||||
| Some x -> x
|
||||
in
|
||||
let shift = !num_digits * shift_right_factor in
|
||||
let without_dot =
|
||||
String.sub s i (k-i)
|
||||
^ (String.sub s first_digit_after_dot (j - first_digit_after_dot))
|
||||
in
|
||||
Z.of_string_base (int_of_base base) without_dot, shift
|
||||
in
|
||||
let shift = shift_left - shift_right in
|
||||
let exponent_pow =
|
||||
match base with
|
||||
| B10 -> 10
|
||||
| B16 -> 2
|
||||
| B8 | B2 -> 1
|
||||
in
|
||||
let abs =
|
||||
if shift < 0 then
|
||||
make z (Z.pow (Z.of_int exponent_pow) (~- shift))
|
||||
else
|
||||
of_bigint (Z.mul z (Z.pow (Z.of_int exponent_pow) shift))
|
||||
in
|
||||
if sign
|
||||
then neg abs
|
||||
else abs
|
||||
in
|
||||
function
|
||||
| "" -> zero
|
||||
| "inf" | "+inf" -> inf
|
||||
| "-inf" -> minus_inf
|
||||
| "undef" -> undef
|
||||
| s ->
|
||||
try
|
||||
let i = String.index s '/' in
|
||||
make
|
||||
(Z.of_substring s ~pos:0 ~len:i)
|
||||
(Z.of_substring s ~pos:(i+1) ~len:(String.length s-i-1))
|
||||
with Not_found ->
|
||||
of_scientific_notation s
|
||||
|
||||
|
||||
|
||||
(* printing *)
|
||||
(* -------- *)
|
||||
|
||||
let print x = print_string (to_string x)
|
||||
let output chan x = output_string chan (to_string x)
|
||||
let sprint () x = to_string x
|
||||
let bprint b x = Buffer.add_string b (to_string x)
|
||||
let pp_print f x = Format.pp_print_string f (to_string x)
|
||||
|
||||
|
||||
(* prefix and infix *)
|
||||
(* ---------------- *)
|
||||
|
||||
let (~-) = neg
|
||||
let (~+) x = x
|
||||
let (+) = add
|
||||
let (-) = sub
|
||||
let ( * ) = mul
|
||||
let (/) = div
|
||||
let (lsl) = mul_2exp
|
||||
let (asr) = div_2exp
|
||||
let (~$) = of_int
|
||||
let (//) = of_ints
|
||||
let (~$$) = of_bigint
|
||||
let (///) = make
|
||||
let (=) = equal
|
||||
let (<) = lt
|
||||
let (>) = gt
|
||||
let (<=) = leq
|
||||
let (>=) = geq
|
||||
let (<>) a b = not (equal a b)
|
||||
Loading…
Add table
Add a link
Reference in a new issue