Mismatch between nextfloat(0.0) and eps(Float64)

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?

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

Also nice:

2 Likes