Dear Julia community,
I am testing the representation of floating point values in my machine. This is the behavior I am seeing:
julia> x = 0.0
0.0
help?> x
(...)
x is of type Float64
(...)
julia> nextfloat(x)
5.0e-324
julia> eps(Float64)
2.220446049250313e-16
My question:
Shouldn’t the outputs of eps(Float64) and nextfloat(x) coincide?
oheil
June 3, 2024, 9:17am
2
The gap between consecutive Float64/32 is not a constant. eps(Float64)
is defined as eps(1.0)
:
julia> eps(0.0)
5.0e-324
julia> nextfloat(0.0)
5.0e-324
julia> eps(1.0)
2.220446049250313e-16
julia> eps(Float64)
2.220446049250313e-16
julia> nextfloat(1.0)
1.0000000000000002
The gap increases for larger Float values.
9 Likes
In particular, consider:
julia> eps(Inf)
NaN
julia> eps(prevfloat(Inf))
1.99584030953472e292
2 Likes
You can think of the value returned by the eps
for the type at large as being like a relative epsilon. It gets scaled by the power of two* of the value you’re looking at. So you have:
julia> eps(1.0) == eps(Float64)
true
julia> eps(16.0) == 16eps(Float64)
true
julia> eps(0.125) == .125eps(Float64)
true
julia> eps(2.0^-1022) == 2.0^-1022*eps(Float64)
true
julia> eps(2.0^1023) == 2.0^1023*eps(Float64)
true
8 Likes
No. The correct definition is myEps(::Type{T}) where T = nextfloat(one(T))-one(T)
. eps
basically counts the significant bits, while nextfloat(zero(T))
counts the exponent bits (up to shennenigans with subnormals).
1 Like
1.1. Floating-point numbers — Fundamentals of Numerical Computation (tobydriscoll.net)
Plugging this here as a pretty good resource for helping to understand floating point representations.
4 Likes