diff options
Diffstat (limited to 'lib/mininix/conv.ml')
-rw-r--r-- | lib/mininix/conv.ml | 96 |
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 @@ | |||
1 | open Core | ||
2 | |||
3 | let _ = assert (Sys.word_size_in_bits = 64) | ||
4 | let chlist s = String.to_list s | ||
5 | let ( <> ) l1 l2 = not (List.equal Char.( = ) l1 l2) | ||
6 | let str = String.of_char_list | ||
7 | let prec = 53 | ||
8 | let emax = 1024 | ||
9 | let exp_bits = 11 | ||
10 | let saturated_exp = Int.shift_left 1 exp_bits - 1 | ||
11 | |||
12 | let 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 | |||
19 | let 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 | |||
29 | let 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 | |||
34 | let 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 | |||
41 | let 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 | |||
47 | let 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 | |||
52 | let 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 | |||
57 | let 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 | |||
75 | let 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 | |||
89 | open 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) | ||
96 | end | ||