diff --git a/base/float.jl b/base/float.jl index f93fee64796fd..8844acd3e0f61 100644 --- a/base/float.jl +++ b/base/float.jl @@ -216,6 +216,24 @@ const NaN32 = box(Float32,unbox(Uint32,0x7fc00000)) const Inf = box(Float64,unbox(Uint64,0x7ff0000000000000)) const NaN = box(Float64,unbox(Uint64,0x7ff8000000000000)) +function float_lex_order(f::Integer, delta::Integer) + # convert from signed magnitude to 2's complement and back + if f < 0 + f = oftype(f, -(f & typemax(f))) + end + f = oftype(f, f + delta) + f < 0 ? oftype(f, -(f & typemax(f))) : f +end + +nextfloat(x::Float16, i::Integer) = + reinterpret(Float16,float_lex_order(reinterpret(Int16,x), i)) +nextfloat(x::Float32, i::Integer) = + reinterpret(Float32,float_lex_order(reinterpret(Int32,x), i)) +nextfloat(x::Float64, i::Integer) = + reinterpret(Float64,float_lex_order(reinterpret(Int64,x), i)) +nextfloat(x::FloatingPoint) = nextfloat(x,1) +prevfloat(x::FloatingPoint) = nextfloat(x,-1) + @eval begin inf(::Type{Float16}) = $Inf16 nan(::Type{Float16}) = $NaN16 @@ -249,12 +267,6 @@ const NaN = box(Float64,unbox(Uint64,0x7ff8000000000000)) realmin() = realmin(Float64) realmax() = realmax(Float64) - nextfloat(x::Float16, i::Integer) = box(Float16,add_int(reinterpret(Int16,x),unbox(Int16,int16(i)))) - nextfloat(x::Float32, i::Integer) = box(Float32,add_int(unbox(Float32,x),unbox(Int32,int32(i)))) - nextfloat(x::Float64, i::Integer) = box(Float64,add_int(unbox(Float64,x),unbox(Int64,int64(i)))) - nextfloat(x::FloatingPoint) = nextfloat(x,1) - prevfloat(x::FloatingPoint) = nextfloat(x,-1) - eps(x::FloatingPoint) = isfinite(x) ? abs(nextfloat(x)-x) : nan(x) eps(::Type{Float16}) = $(box(Float16,unbox(Uint16,0x1400))) eps(::Type{Float32}) = $(box(Float32,unbox(Uint32,0x34000000))) diff --git a/test/numbers.jl b/test/numbers.jl index 475a1309db12c..882e46778795e 100644 --- a/test/numbers.jl +++ b/test/numbers.jl @@ -1162,22 +1162,22 @@ end @test iround(Int, 0.5) == 1 @test iround(Int, prevfloat(0.5)) == 0 @test iround(Int, -0.5) == -1 -@test iround(Int, prevfloat(-0.5)) == 0 +@test iround(Int, nextfloat(-0.5)) == 0 @test iround(Uint, 0.5) == 1 @test iround(Uint, prevfloat(0.5)) == 0 @test_throws iround(Uint, -0.5) -@test iround(Uint, prevfloat(-0.5)) == 0 +@test iround(Uint, nextfloat(-0.5)) == 0 @test iround(Int, 0.5f0) == 1 @test iround(Int, prevfloat(0.5f0)) == 0 @test iround(Int, -0.5f0) == -1 -@test iround(Int, prevfloat(-0.5f0)) == 0 +@test iround(Int, nextfloat(-0.5f0)) == 0 @test iround(Uint, 0.5f0) == 1 @test iround(Uint, prevfloat(0.5f0)) == 0 @test_throws iround(Uint, -0.5f0) -@test iround(Uint, prevfloat(-0.5f0)) == 0 +@test iround(Uint, nextfloat(-0.5f0)) == 0 # numbers that can't be rounded by trunc(x+0.5) @test iround(Int64, 2.0^52 + 1) == 4503599627370497 @@ -1579,3 +1579,14 @@ end @test nextprod([2,3,5],30) == 30 @test nextprod([2,3,5],33) == 36 + +@test nextfloat(0.0) == 5.0e-324 +@test prevfloat(0.0) == -5.0e-324 +@test nextfloat(-0.0) == 5.0e-324 +@test prevfloat(-0.0) == -5.0e-324 +@test nextfloat(-5.0e-324) == 0.0 +@test prevfloat(5.0e-324) == 0.0 +@test nextfloat(-1.0) > -1.0 +@test prevfloat(-1.0) < -1.0 +@test nextfloat(nextfloat(0.0),-2) == -5.0e-324 +@test nextfloat(prevfloat(0.0), 2) == 5.0e-324