Source file number_parsing.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
let is_hex c = ('0' <= c && c <= '9') || ('A' <= c && c <= 'F')
let is_exp hex c = c = if hex then 'P' else 'E'
let at_end hex s i = i = String.length s || is_exp hex s.[i]
let rec skip_non_hex s i =
if at_end true s i || is_hex s.[i] then i else skip_non_hex s (i + 1)
let rec skip_zeroes s i =
let i' = skip_non_hex s i in
if at_end true s i' || s.[i'] <> '0' then i' else skip_zeroes s (i' + 1)
let rec compare_mantissa_str' hex s1 i1 s2 i2 =
let i1' = skip_non_hex s1 i1 in
let i2' = skip_non_hex s2 i2 in
match (at_end hex s1 i1', at_end hex s2 i2') with
| true, true -> 0
| true, false -> if at_end hex s2 (skip_zeroes s2 i2') then 0 else -1
| false, true -> if at_end hex s1 (skip_zeroes s1 i1') then 0 else 1
| false, false -> (
match compare s1.[i1'] s2.[i2'] with
| 0 -> compare_mantissa_str' hex s1 (i1' + 1) s2 (i2' + 1)
| n -> n)
let compare_mantissa_str hex s1 s2 =
let s1' = String.uppercase_ascii s1 in
let s2' = String.uppercase_ascii s2 in
compare_mantissa_str' hex s1' (skip_zeroes s1' 0) s2' (skip_zeroes s2' 0)
let midpoint_string hex s az =
if not hex then Printf.sprintf "%.*g" (String.length s) az
else
let open Int64 in
let bits = bits_of_float az in
let mantissa =
logor (logand bits 0xf_ffff_ffff_ffffL) 0x10_0000_0000_0000L
in
let i = skip_zeroes (String.uppercase_ascii s) 0 in
if i = String.length s then Printf.sprintf "%.*g" (String.length s) az
else
let sh =
match s.[i] with '1' -> 0 | '2' .. '3' -> 1 | '4' .. '7' -> 2 | _ -> 3
in
Printf.sprintf "%Lx" (shift_left mantissa sh)
let float32_of_string s =
let z = float_of_string s in
if (not (Float.is_finite z)) || z = 0.0 then z
else
let neg = z < 0.0 in
let az = Float.abs z in
let f = Int32.bits_of_float az in
let fz = Int32.float_of_bits f in
let mag =
if az = fz then az
else
let other = if az > fz then Int32.add f 1l else Int32.sub f 1l in
let fo = Int32.float_of_bits other in
let m =
if Float.is_finite fz && Float.is_finite fo then (fz +. fo) *. 0.5
else
0x1.ffffffp127
in
if az <> m then az
else
let hex = String.contains s 'x' in
match compare_mantissa_str hex s (midpoint_string hex s az) with
| 0 -> az
| c when c > 0 ->
Float.max fz fo
| _ -> Float.min fz fo
in
if neg then -.mag else mag
let float32_bits s =
let len = String.length s in
let has_sign = len > 0 && (s.[0] = '-' || s.[0] = '+') in
let offset = if has_sign then 1 else 0 in
if len > offset + 4 && String.sub s offset 4 = "nan:" then
let payload =
Int64.of_string (String.sub s (offset + 4) (len - offset - 4))
in
let sign = if s.[0] = '-' then 0x80000000l else 0l in
Int32.logor
(Int32.logor sign 0x7F800000l)
(Int64.to_int32 (Int64.logand payload 0x7FFFFFL))
else Int32.bits_of_float (float32_of_string s)
let float64 s =
let len = String.length s in
let has_sign = len > 0 && (s.[0] = '-' || s.[0] = '+') in
let offset = if has_sign then 1 else 0 in
if len > offset + 4 && String.sub s offset 4 = "nan:" then
let payload =
Int64.of_string (String.sub s (offset + 4) (len - offset - 4))
in
let sign_bit = if s.[0] = '-' then 1L else 0L in
let bits =
Int64.logor
(Int64.logor
(Int64.shift_left sign_bit 63)
(Int64.shift_left 0x7FFL 52))
(Int64.logand payload 0xFFFFFFFFFFFFFL)
in
Int64.float_of_bits bits
else float_of_string s
let int_conv conv s = try conv s with Failure _ -> conv ("0u" ^ s)
let int32 s = int_conv Int32.of_string s
let int64 s = int_conv Int64.of_string s