Skip to content

Commit 7600833

Browse files
authored
initial code.
1 parent 18bc52d commit 7600833

File tree

1 file changed

+99
-0
lines changed

1 file changed

+99
-0
lines changed
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
using Base.Math: significand_bits, exponent_bias
2+
using Test, Printf
3+
4+
struct FloatIterator{T}<:AbstractVector{T}
5+
min::T
6+
max::T
7+
FloatIterator{T}(min, max) where T = min > max ? error("max less than min") : new{T}(min,max)
8+
end
9+
10+
FloatIterator{T}() where T = FloatIterator{T}(T(-Inf),T(Inf))
11+
Base.iterate(it::FloatIterator) = (it.min, nextfloat(it.min))
12+
function Base.iterate(it::FloatIterator{T}, el) where T
13+
return el == it.max ? nothing : (el, nextfloat(el))
14+
end
15+
16+
function Base.size(it::FloatIterator{T}) where T
17+
if isless(it.max, 0.0)
18+
size = reinterpret(Base.uinttype(T), it.max) - reinterpret(Base.uinttype(T), it.min)
19+
elseif isless(-0.0, it.min)
20+
size = reinterpret(Base.uinttype(T), it.max) - reinterpret(Base.uinttype(T), it.min)
21+
else
22+
size = reinterpret(Base.uinttype(T), it.max)
23+
size += reinterpret(Base.uinttype(T), it.min) - reinterpret(Base.uinttype(T), T(-0.0))
24+
end
25+
return (size+1,)
26+
end
27+
28+
Base.getindex(it::FloatIterator{T}, i::Int) where T = nextfloat(it.min, i-1)
29+
Base.show(io::IO, mime::MIME"text/plain", it::FloatIterator) = show(io, it)
30+
Base.show(io::IO, it::FloatIterator) = print(io, "FloatIterator(", it.min, ", ", it.max, ")")
31+
32+
# the following compares the ulp between x and y.
33+
# First it promotes them to the larger of the two types x,y
34+
const infh(T) = prevfloat(T(Inf),4)
35+
function countulp(T, x::AbstractFloat, y::AbstractFloat)
36+
X, Y = promote(x, y)
37+
x, y = T(X), T(Y) # Cast to smaller type
38+
(isnan(x) && isnan(y)) && return 0
39+
(isnan(x) || isnan(y)) && return 10000
40+
if isinf(x)
41+
(sign(x) == sign(y) && abs(y) > infh(T)) && return 0 # relaxed infinity handling
42+
return 10001
43+
end
44+
(x == Inf && y == Inf) && return 0
45+
(x == -Inf && y == -Inf) && return 0
46+
if y == 0
47+
x == 0 && return 0
48+
return 10002
49+
end
50+
if isfinite(x) && isfinite(y)
51+
return T(abs(X - Y) / ulp(y))
52+
end
53+
return 10003
54+
end
55+
56+
const DENORMAL_MIN(::Type{Float64}) = 2.0^-1074
57+
const DENORMAL_MIN(::Type{Float32}) = 2f0^-149
58+
const DENORMAL_MIN(::Type{Float16}) = Float16(6.0e-8)
59+
60+
function ulp(x::T) where {T<:AbstractFloat}
61+
x = abs(x)
62+
x == T(0.0) && return DENORMAL_MIN(T)
63+
val, e = frexp(x)
64+
return max(ldexp(T(1.0), e - significand_bits(T) - 1), DENORMAL_MIN(T))
65+
end
66+
67+
countulp(x::T, y::T) where {T <: AbstractFloat} = countulp(T, x, y)
68+
strip_module_name(f::Function) = last(split(string(f), '.')) # strip module name from function f
69+
70+
function test_acc(fun_table, xx, tol; debug = true, tol_debug = 5)
71+
@testset "accuracy $(strip_module_name(xfun))" for (xfun, fun) in fun_table
72+
rmax = 0.0
73+
rmean = 0.0
74+
xmax = map(zero, first(xx))
75+
tol_debug_failed = 0
76+
for x in xx
77+
q = xfun(x...)
78+
c = fun(map(big, x)...)
79+
u = countulp(T, q, c)
80+
rmax = max(rmax, u)
81+
xmax = rmax == u ? x : xmax
82+
rmean += u
83+
if debug && u > tol_debug
84+
tol_debug_failed += 1
85+
#@printf("%s = %.20g\n%s = %.20g\nx = %.20g\nulp = %g\n", strip_module_name(xfun), q, strip_module_name(fun), T(c), x, u)
86+
end
87+
end
88+
if debug
89+
println("Tol debug failed $(100tol_debug_failed / length(xx))% of the time.")
90+
end
91+
rmean = rmean / length(xx)
92+
println(strip_module_name(xfun))
93+
println("max $rmax at x = $xmax")
94+
println("mean $rmean")
95+
t = @test rmax <= tol
96+
end
97+
end
98+
test_acc(fun_table, xx, tol; debug = true, tol_debug = 5) = test_acc(eltype(xx), fun_table, xx, 1.5; debug = true, tol_debug = 5)
99+
test_acc(fun_table, xx; debug = true, tol_debug = 5) = test_acc(fun_table, xx, 1.5; debug = true, tol_debug = 5)

0 commit comments

Comments
 (0)