Skip to content

Commit 6c55489

Browse files
committed
Float_u stdlib tests
1 parent f654bb9 commit 6c55489

File tree

1 file changed

+269
-0
lines changed

1 file changed

+269
-0
lines changed
Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
1+
(* TEST
2+
flags = "-extension layouts_alpha"
3+
*)
4+
5+
module Float_u = Stdlib__Float_u
6+
7+
(* Constant seed for repeatable random-testing properties *)
8+
let () = Random.init 1234
9+
10+
type 'a result = {
11+
actual : 'a;
12+
expected : 'a;
13+
equal : 'a -> 'a -> bool;
14+
to_string : 'a -> string
15+
}
16+
17+
let float_result ~actual ~expected = {
18+
actual;
19+
expected;
20+
equal = Float.equal;
21+
to_string = Float.to_string;
22+
}
23+
24+
let bool_result ~actual ~expected = {
25+
actual;
26+
expected;
27+
equal = Bool.equal;
28+
to_string = Bool.to_string;
29+
}
30+
31+
let int_result ~actual ~expected = {
32+
actual;
33+
expected;
34+
equal = Int.equal;
35+
to_string = Int.to_string;
36+
}
37+
38+
let string_result ~actual ~expected = {
39+
actual;
40+
expected;
41+
equal = String.equal;
42+
to_string = fun x -> x;
43+
}
44+
45+
let fpclass_to_string = function
46+
FP_normal -> "FP_normal"
47+
| FP_subnormal -> "FP_subnormal"
48+
| FP_zero -> "FP_zero"
49+
| FP_infinite -> "FP_infinite"
50+
| FP_nan -> "FP_nan"
51+
52+
let fpclass_result ~actual ~expected = {
53+
actual;
54+
expected;
55+
equal = (=);
56+
to_string = fpclass_to_string;
57+
}
58+
59+
let interesting_floats =
60+
[ 0.; 1.; -1.; Float.max_float; Float.min_float; Float.epsilon;
61+
Float.nan; Float.infinity; Float.neg_infinity ]
62+
63+
let interesting_ints = [ 0; 1; -1; Int.max_int; Int.min_int ]
64+
65+
let default_min = -10000.
66+
let default_max = 10000.
67+
68+
let floats_in_range ~num min max =
69+
(* Generating well-distributed random floats in a range is obviously hard.
70+
The "in a range" part is important because many float functions are only
71+
defined on certain ranges. I'm not trying very hard, here - this should
72+
only be used with min and max that aren't at the outer limits of the float
73+
range. *)
74+
let float_in_range () =
75+
let f = Random.float 1000. in
76+
let f = f *. ((max -. min) /. 1000.) in
77+
f +. min
78+
in
79+
List.init num (fun _ -> float_in_range ())
80+
81+
let float_inputs ~range ~num =
82+
let min, max =
83+
match range with
84+
| None -> default_min, default_max
85+
| Some (min, max) -> min, max
86+
in
87+
let input = floats_in_range ~num min max in
88+
let input =
89+
if Option.is_none range then interesting_floats @ input else input
90+
in
91+
input
92+
93+
let string_inputs ~num =
94+
List.map Float.to_string (float_inputs ~range:None ~num)
95+
96+
let int_inputs ~num =
97+
let gen_int _ = (Random.full_int Int.max_int) - (Int.max_int / 2) in
98+
interesting_ints @ List.init num gen_int
99+
100+
let passed { actual; expected; equal; _ } = equal actual expected
101+
102+
let test inputs input_to_string name prop =
103+
let test x =
104+
let {expected; actual; to_string} as result = prop x in
105+
if not (passed result)
106+
then
107+
Printf.printf "Test failed: %s. Input = %s; expected = %s; actual = %s\n"
108+
name (input_to_string x) (to_string expected) (to_string actual)
109+
in
110+
List.iter test inputs
111+
112+
(* zips that truncate *)
113+
let rec zip l1 l2 =
114+
match l1, l2 with
115+
| x1 :: l1, x2 :: l2 -> (x1, x2) :: zip l1 l2
116+
| _ -> []
117+
118+
let rec zip3 l1 l2 l3 =
119+
match l1, l2, l3 with
120+
| x1 :: l1, x2 :: l2, x3 :: l3 -> (x1, x2, x3) :: zip3 l1 l2 l3
121+
| _ -> []
122+
123+
(* These run a property on inputs and check the result *)
124+
let test_unary ?range name prop =
125+
let inputs = float_inputs ~range ~num:10 in
126+
let input_to_string = Float.to_string in
127+
test inputs input_to_string name prop
128+
129+
let test_unary_int ?range name prop =
130+
let inputs = int_inputs ~num:10 in
131+
let input_to_string = Int.to_string in
132+
test inputs input_to_string name prop
133+
134+
let test_unary_string ?range name prop =
135+
let inputs = string_inputs ~num:10 in
136+
let input_to_string x = x in
137+
test inputs input_to_string name prop
138+
139+
let test_binary ?range name prop =
140+
let input1 = float_inputs ~range ~num:20 in
141+
let input2 = List.rev (float_inputs ~range ~num:20) in
142+
let inputs = zip input1 (List.rev input2) in
143+
let input_to_string (f1,f2) = Printf.sprintf "(%f, %f)" f1 f2 in
144+
test inputs input_to_string name prop
145+
146+
let test_binary_float_int ?range name prop =
147+
let input1 = float_inputs ~range ~num:20 in
148+
let input2 = List.rev (int_inputs ~num:20) in
149+
let inputs = zip input1 (List.rev input2) in
150+
let input_to_string (f1,f2) = Printf.sprintf "(%f, %d)" f1 f2 in
151+
test inputs input_to_string name prop
152+
153+
let test_ternary ?range name prop =
154+
let input1 = float_inputs ~range ~num:30 in
155+
let input2 = float_inputs ~range ~num:30 in
156+
let input3 = List.rev (float_inputs ~range ~num:30) in
157+
let inputs = zip3 input1 input2 input3 in
158+
let input_to_string (f1, f2, f3) = Printf.sprintf "(%f, %f, %f)" f1 f2 f3 in
159+
test inputs input_to_string name prop
160+
161+
(* These make the property to be tested for various arities and types *)
162+
let mk1 expected_f actual_f arg =
163+
let expected = expected_f arg in
164+
let actual = Float_u.to_float (actual_f (Float_u.of_float arg)) in
165+
float_result ~actual ~expected
166+
167+
let mk2 expected_f actual_f (arg1, arg2) =
168+
let expected = expected_f arg1 arg2 in
169+
let actual =
170+
Float_u.to_float
171+
(actual_f (Float_u.of_float arg1) (Float_u.of_float arg2))
172+
in
173+
float_result ~actual ~expected
174+
175+
let mk3 expected_f actual_f (arg1, arg2, arg3) =
176+
let expected = expected_f arg1 arg2 arg3 in
177+
let actual =
178+
Float_u.to_float
179+
(actual_f (Float_u.of_float arg1) (Float_u.of_float arg2)
180+
(Float_u.of_float arg3))
181+
in
182+
float_result ~actual ~expected
183+
184+
let mk_float_X result expected_f actual_f arg =
185+
let expected = expected_f arg in
186+
let actual = actual_f (Float_u.of_float arg) in
187+
result ~actual ~expected
188+
189+
let mk_X_float expected_f actual_f arg =
190+
let expected = expected_f arg in
191+
let actual = Float_u.to_float (actual_f arg) in
192+
float_result ~actual ~expected
193+
194+
let mk_float_X_float expected_f actual_f (arg1, arg2) =
195+
let expected = expected_f arg1 arg2 in
196+
let actual = Float_u.to_float (actual_f (Float_u.of_float arg1) arg2) in
197+
float_result ~actual ~expected
198+
199+
let mk_float_float_X result expected_f actual_f (arg1, arg2) =
200+
let expected = expected_f arg1 arg2 in
201+
let actual = actual_f (Float_u.of_float arg1) (Float_u.of_float arg2) in
202+
result ~actual ~expected
203+
204+
let () =
205+
test_unary "neg" (mk1 Float.neg Float_u.neg);
206+
test_binary "add" (mk2 Float.add Float_u.add);
207+
test_binary "sub" (mk2 Float.sub Float_u.sub);
208+
test_binary "mul" (mk2 Float.mul Float_u.mul);
209+
test_binary "div" (mk2 Float.div Float_u.div);
210+
test_ternary "fma" (mk3 Float.fma Float_u.fma);
211+
test_binary "rem" (mk2 Float.rem Float_u.rem);
212+
test_unary "succ" (mk1 Float.succ Float_u.succ);
213+
test_unary "pred" (mk1 Float.pred Float_u.pred);
214+
test_unary "abs" (mk1 Float.abs Float_u.abs);
215+
test_unary "is_finite"
216+
(mk_float_X bool_result Float.is_finite Float_u.is_finite);
217+
test_unary "is_nan" (mk_float_X bool_result Float.is_nan Float_u.is_nan);
218+
test_unary "is_integer"
219+
(mk_float_X bool_result Float.is_integer Float_u.is_integer);
220+
test_unary_int "of_int" (mk_X_float Float.of_int Float_u.of_int);
221+
test_unary "to_int" (mk_float_X int_result Float.to_int Float_u.to_int);
222+
test_unary_string "of_string" (mk_X_float Float.of_string Float_u.of_string);
223+
test_unary "to_string"
224+
(mk_float_X string_result Float.to_string Float_u.to_string);
225+
test_unary "classify_float"
226+
(mk_float_X fpclass_result Float.classify_float Float_u.classify_float);
227+
test_binary "pow" (mk2 Float.pow Float_u.pow);
228+
test_unary "sqt" (mk1 Float.sqrt Float_u.sqrt);
229+
test_unary "cbrt" (mk1 Float.cbrt Float_u.cbrt);
230+
test_unary "exp" (mk1 Float.exp Float_u.exp);
231+
test_unary "exp2" (mk1 Float.exp2 Float_u.exp2);
232+
test_unary "log" (mk1 Float.log Float_u.log);
233+
test_unary "log10" (mk1 Float.log10 Float_u.log10);
234+
test_unary "log2" (mk1 Float.log2 Float_u.log2);
235+
test_unary "log1p" (mk1 Float.log1p Float_u.log1p);
236+
test_unary "cos" (mk1 Float.cos Float_u.cos);
237+
test_unary "sin" (mk1 Float.sin Float_u.sin);
238+
test_unary "tan" (mk1 Float.tan Float_u.tan);
239+
test_unary "acos" ~range:(-1.0, 1.0) (mk1 Float.acos Float_u.acos);
240+
test_unary "asin" ~range:(-1.0, 1.0) (mk1 Float.asin Float_u.asin);
241+
test_unary "atan" (mk1 Float.atan Float_u.atan);
242+
test_binary "atan2" (mk2 Float.atan2 Float_u.atan2);
243+
test_binary "hypot" (mk2 Float.hypot Float_u.hypot);
244+
test_unary "cosh" (mk1 Float.cosh Float_u.cosh);
245+
test_unary "sinh" (mk1 Float.sinh Float_u.sinh);
246+
test_unary "tanh" (mk1 Float.tanh Float_u.tanh);
247+
test_unary "acosh" ~range:(1.0, Float.infinity)
248+
(mk1 Float.acosh Float_u.acosh);
249+
test_unary "asinh" (mk1 Float.asinh Float_u.asinh);
250+
test_unary "atanh" ~range:(-1.0, 1.0) (mk1 Float.atanh Float_u.atanh);
251+
test_unary "erf" (mk1 Float.erf Float_u.erf);
252+
test_unary "erfc" (mk1 Float.erfc Float_u.erfc);
253+
test_unary "trunk" (mk1 Float.trunc Float_u.trunc);
254+
test_unary "round" (mk1 Float.round Float_u.round);
255+
test_unary "ceil" (mk1 Float.ceil Float_u.ceil);
256+
test_unary "floor" (mk1 Float.floor Float_u.floor);
257+
test_binary "next_after" (mk2 Float.next_after Float_u.next_after);
258+
test_binary "copy_sign" (mk2 Float.copy_sign Float_u.copy_sign);
259+
test_unary "sign_bit"
260+
(mk_float_X bool_result Float.sign_bit Float_u.sign_bit);
261+
test_binary_float_int "ldexp" (mk_float_X_float Float.ldexp Float_u.ldexp);
262+
test_binary "compare"
263+
(mk_float_float_X int_result Float.compare Float_u.compare);
264+
test_binary "equal"
265+
(mk_float_float_X bool_result Float.equal Float_u.equal);
266+
test_binary "min" (mk2 Float.min Float_u.min);
267+
test_binary "max" (mk2 Float.max Float_u.max);
268+
test_binary "min_num" (mk2 Float.min_num Float_u.min_num);
269+
test_binary "max_num" (mk2 Float.max_num Float_u.max_num);

0 commit comments

Comments
 (0)