-
Notifications
You must be signed in to change notification settings - Fork 9
/
func.ml
116 lines (99 loc) · 3.1 KB
/
func.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
open Interval
let asinh x = log (x +. sqrt (x *. x +. 1.0))
let acosh x = log (x +. sqrt (x *. x -. 1.0))
let atanh x = 0.5 *. log ((1.0 +. x) /. (1.0 -. x))
let asinh_I x = {
low =
(let sqrt = Fpu.fsqrt_low (Fpu.fadd_low (Fpu.fmul_low x.low x.low) 1.0) in
Fpu.flog_low (Fpu.fadd_low x.low sqrt));
high =
(let sqrt = Fpu.fsqrt_high (Fpu.fadd_high (Fpu.fmul_high x.high x.high) 1.0) in
Fpu.flog_high (Fpu.fadd_high x.high sqrt));
}
let acosh_I x =
if x.high < 1.0 then failwith "acosh_I"
else {
low =
(if x.low <= 1.0 then 0.0
else
let sqrt = Fpu.fsqrt_low (Fpu.fsub_low (Fpu.fmul_low x.low x.low) 1.0) in
Fpu.flog_low (Fpu.fadd_low x.low sqrt));
high =
(let sqrt = Fpu.fsqrt_high (Fpu.fsub_high (Fpu.fmul_high x.high x.high) 1.0) in
Fpu.flog_high (Fpu.fadd_high x.high sqrt));
}
let atanh_I x =
if x.high < -1.0 || x.low > 1.0 then failwith "atanh_I"
else {
low =
(if x.low <= -1.0 then neg_infinity
else
let t = Fpu.fdiv_low (Fpu.fadd_low 1.0 x.low) (Fpu.fsub_high 1.0 x.low) in
Fpu.fmul_low 0.5 (Fpu.flog_low t));
high =
(if x.high >= 1.0 then infinity
else
let t = Fpu.fdiv_high (Fpu.fadd_high 1.0 x.high) (Fpu.fsub_low 1.0 x.high) in
Fpu.fmul_high 0.5 (Fpu.flog_high t));
}
(* For a given positive floating-point number f,
returns the largest floating-point number 2^n such that
2^n < f.
*)
let floor_power2 =
let p2 f =
let s, q = frexp f in
if s = 0.5 then
ldexp 1.0 (q - 2)
else
ldexp 1.0 (q - 1) in
fun f ->
match (classify_float f) with
| FP_zero -> f
| FP_infinite -> f
| FP_nan -> f
| FP_normal | FP_subnormal ->
if f < 0.0 then -.p2 (-.f) else p2 f
let floor_power2_I x = {
low = floor_power2 x.low;
high = floor_power2 x.high
}
let goldberg_ulp (prec, e_min) =
let ulp f =
let _, e = frexp f in
ldexp 1.0 (max e (e_min + 1) - prec) in
fun f ->
match (classify_float f) with
| FP_zero | FP_infinite | FP_nan -> f
| FP_subnormal | FP_normal ->
if f < 0. then -.ulp(-.f) else ulp f
let goldberg_ulp_I pars x = {
low = goldberg_ulp pars x.low;
high = goldberg_ulp pars x.high
}
let sub2 (x, y) =
if (0.5 *. x <= y && y <= 2.0 *. x) ||
(2.0 *. x <= y && y <= 0.5 *. x)
then 0.0
else x -. y
let sub2_I (x, y) = {
low = if (0.5 *. x.low <= y.high && y.high <= 2.0 *. x.low) ||
(2.0 *. x.low <= y.high && y.high <= 0.5 *. x.low)
then 0.0
else Fpu.fsub_low x.low y.high;
high = if (0.5 *. x.high <= y.low && y.low <= 2.0 *. x.high) ||
(2.0 *. x.high <= y.low && y.low <= 0.5 *. x.high)
then 0.0
else Fpu.fsub_high x.high y.low;
}
let abs_err (t, x) =
if x >= t then 1.
else if x <= -.t then -1.
else 0. (* should be [-1, 1] but we cannot return an interval here;
this function is not important *)
let neg_one_I = {low = -1.; high = -1.}
let neg_one_one_I = {low = -1.; high = 1.}
let abs_err_I (t, x) =
if x.low >= t.high then one_I
else if x.high <= t.low then neg_one_I
else neg_one_one_I