aboutsummaryrefslogtreecommitdiffstats
path: root/lib/mininix/conv.ml
diff options
context:
space:
mode:
Diffstat (limited to 'lib/mininix/conv.ml')
-rw-r--r--lib/mininix/conv.ml96
1 files changed, 96 insertions, 0 deletions
diff --git a/lib/mininix/conv.ml b/lib/mininix/conv.ml
new file mode 100644
index 0000000..8062099
--- /dev/null
+++ b/lib/mininix/conv.ml
@@ -0,0 +1,96 @@
1open Core
2
3let _ = assert (Sys.word_size_in_bits = 64)
4let chlist s = String.to_list s
5let ( <> ) l1 l2 = not (List.equal Char.( = ) l1 l2)
6let str = String.of_char_list
7let prec = 53
8let emax = 1024
9let exp_bits = 11
10let saturated_exp = Int.shift_left 1 exp_bits - 1
11
12let rec int_bits (x : int) : bool list =
13 if Int.(x < 0) then raise (Invalid_argument "Number must be nonnegative")
14 else if Int.(x = 0) then []
15 else
16 let q = x /% 2 and r = x % 2 in
17 int_bits q @ [ r = 1 ]
18
19let int_to_positive (x : int) : Extraction.Internal.BinNums.positive =
20 if x <= 0 then raise (Invalid_argument "Number must be positive")
21 else
22 let bits = List.tl_exn (int_bits x) in
23 List.fold_left
24 ~f:(fun acc digit ->
25 if digit then Extraction.Internal.BinNums.Coq_xI acc
26 else Extraction.Internal.BinNums.Coq_xO acc)
27 ~init:Extraction.Internal.BinNums.Coq_xH bits
28
29let int_to_z (x : int) : Extraction.Internal.BinNums.coq_Z =
30 if x = 0 then Z0
31 else if x < 0 then Zneg (int_to_positive (-x))
32 else Zpos (int_to_positive x)
33
34let rec int63_of_positive (x : Extraction.Internal.BinNums.positive) : Int63.t =
35 let two = Int63.(succ one) in
36 match x with
37 | Coq_xH -> Int63.of_int_exn 1
38 | Coq_xO x -> Int63.(two * int63_of_positive x)
39 | Coq_xI x -> Int63.((two * int63_of_positive x) + one)
40
41let int63_of_z (x : Extraction.Internal.BinNums.coq_Z) : Int63.t =
42 match x with
43 | Z0 -> Int63.zero
44 | Zpos x -> int63_of_positive x
45 | Zneg x -> Int63.neg (int63_of_positive x)
46
47let int63_to_positive x = Int63.to_int_exn x |> int_to_positive
48
49(* Conversions are the same as those in Coq's FloatOps.
50 See https://github.com/coq/coq/blob/master/theories/Floats/FloatOps.v *)
51
52let normfr_mantissa f =
53 let f = Float.abs f in
54 if Float.(f >= 0.5) && Float.(f < 1.) then Float.to_int (Float.ldexp f prec)
55 else 0
56
57let float_to_flocq (x : float) : Extraction.Internal.Floats.float =
58 match Float.classify x with
59 | Zero -> Extraction.Internal.Floats.B754_zero (Float.ieee_negative x)
60 | Nan ->
61 Extraction.Internal.Floats.B754_nan
62 (Float.ieee_negative x, Float.ieee_mantissa x |> int63_to_positive)
63 | Infinite -> Extraction.Internal.Floats.B754_infinity (Float.ieee_negative x)
64 | Normal | Subnormal -> (
65 let prec_z = int_to_z prec and emax_z = int_to_z emax in
66 let r, exp = Float.frexp x in
67 let e = int_to_z (exp - prec) and r' = int_to_z (normfr_mantissa r) in
68 let shr, e' =
69 Extraction.Internal.Floats.(shr_fexp prec_z emax_z r' e Coq_loc_Exact)
70 in
71 match shr.shr_m with
72 | Zpos p -> B754_finite (Float.is_negative x, p, e')
73 | Zneg _ | Z0 -> assert false)
74
75let float_from_flocq x : float =
76 match x with
77 | Extraction.Internal.Floats.B754_zero s ->
78 Float.create_ieee_exn ~negative:s ~mantissa:Int63.zero ~exponent:0
79 | Extraction.Internal.Floats.B754_infinity s ->
80 if s then Float.neg_infinity else Float.infinity
81 | Extraction.Internal.Floats.B754_nan (s, m) ->
82 let m_int = int63_of_positive m in
83 Float.create_ieee_exn ~negative:s ~mantissa:m_int ~exponent:saturated_exp
84 | Extraction.Internal.Floats.B754_finite (s, m, e) ->
85 let pm = Float.of_int63 (int63_of_positive m) in
86 let f = Float.ldexp pm (Int63.to_int_exn (int63_of_z e)) in
87 if s then Float.neg f else f
88
89open struct
90 open Base_quickcheck
91
92 let%expect_test "float conversion" =
93 Test.run_exn
94 (module Float)
95 ~f:(fun x -> [%test_eq: float] (float_from_flocq (float_to_flocq x)) x)
96end