Skip to content

Commit 502f1d3

Browse files
Rectify incorrect values produced on range (2.0, 2.000001907348633)
See notes in added tests
1 parent f0ed72f commit 502f1d3

File tree

3 files changed

+65
-4
lines changed

3 files changed

+65
-4
lines changed

src/logabsgamma/e_lgamma_r.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,10 +113,10 @@ function _logabsgamma(x::Float64)
113113
if t < 0.0; signgam = -1; end
114114
x = -x
115115
end
116-
if ix 0x40000000 #= for 1.0 ≤ x ≤ 2.0 =#
116+
if ix < 0x40000000 #= x < 2.0 =#
117117
i = round(x, RoundToZero)
118118
f = x - i
119-
if f == 0.0 #= purge off 1 and 2 =#
119+
if f == 0.0 #= purge off 1; 2 handled by x < 8.0 branch =#
120120
return 0.0, signgam
121121
elseif i == 1.0
122122
r = 0.0

src/logabsgamma/e_lgammaf_r.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,10 @@ function _logabsgamma(x::Float32)
4242
x = -x
4343
end
4444

45-
if ix 0x40000000 #= for 1.0 ≤ x ≤ 2.0 =#
45+
if ix < 0x40000000 #= x < 2.0 =#
4646
i = round(x, RoundToZero)
4747
f = x - i
48-
if f == 0.0f0 #= purge off 1 and 2 =#
48+
if f == 0.0f0 #= purge off 1; 2 handled by x < 8.0 branch =#
4949
return 0.0f0, signgam
5050
elseif i == 1.0f0
5151
r = 0.0f0

test/logabsgamma.jl

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,3 +93,64 @@ end
9393
@test meetstol(2.1f0^-71, 1f-6)
9494
@test meetstol(2.0f0^60, 1e-15)
9595
end
96+
97+
#### A few critical values, but first, a few useful functions
98+
ixword(x::Float64) = (reinterpret(UInt64, x) >>> 32 & Int32) & 0x7fffffff
99+
ixword(x::Float32) = reinterpret(Int32, x) & 0x7fffffff
100+
101+
function ulp(x::Float32)
102+
z′ = logabsgamma(x)[1]
103+
z = logabsgamma(Float64(x))[1] # Test against our Float64 implementation
104+
isinf(z′) && isinf(oftype(x, z)) && return 0.0
105+
iszero(z′) && iszero(z) && return 0.0
106+
e = exponent(z′)
107+
abs(z′ - z) * 2.0^(precision(x) - 1 - e)
108+
end
109+
function ulp(x)
110+
z′ = logabsgamma(x)[1]
111+
z = logabsgamma(big(x))[1] # Dispatches to MPFR
112+
isinf(z′) && isinf(oftype(x, z)) && return big(0.0)
113+
iszero(z′) && iszero(z) && return big(0.0)
114+
e = exponent(z′)
115+
abs(z′ - z) * 2.0^(precision(x) - 1 - e)
116+
end
117+
118+
119+
# interval: 0 < x < 2
120+
# First f64 which would not satisfy ixword(x) ≤ 0x40000000:
121+
x = 2.000001907348633
122+
# That is, all values between 2.0 and 2.000001907348633 would inappropriately fall
123+
# into the trap of ≤ 0x40000000, thereby producing completely incorrect values.
124+
# Hence, we must carefully test to ensure that this small region is computed
125+
# appropriately.
126+
127+
@test ulp(x) < 0.1511442187367193
128+
@test ulp(2.0) == 0.0
129+
r = 2.0:1e-9:prevfloat(x)
130+
@test all(x -> ulp(x) < 1.0, r)
131+
132+
# first f32 greater than 2.0f0:
133+
x = 2.0000002f0
134+
@test ulp(x) < 0.197537131607533
135+
# unlike f64, the representable distance between values is too small to matter
136+
# -- i.e. prevfloat(2.0000002f0) == 2.0f0; we check behavior anyway
137+
@test ulp(2.0f0) == 0.0
138+
139+
140+
# interval: 2 < x < 8
141+
# In fact, the first f64 which does not fall into the x < 8.0 branch is:
142+
x = 8.000007629394531
143+
@test ulp(prevfloat(x)) < 0.625524448102362
144+
@test ulp(x) < 0.390118045607547
145+
# This is overkill, but should reveal any toying around with this
146+
# sensitive region.
147+
r = 8.0:1e-9:prevfloat(x)
148+
@test all(x -> ulp(x) < 1.5, r)
149+
150+
# first f32 which does not fall into x < 8.0 branch is:
151+
x = 8.000001f0
152+
@test ulp(x) < 0.614982068538667
153+
# But, unlike f64, the representable distance between values is too small.
154+
# (i.e. prevfloat(8.000001f0) == 8.0f0)
155+
# We still check appropriate behavior at 8.0f0
156+
@test ulp(8.0f0) < 0.4006594736129046

0 commit comments

Comments
 (0)