diff --git a/base/gmp.jl b/base/gmp.jl index 90a7161c64594..605ab5dd1539b 100644 --- a/base/gmp.jl +++ b/base/gmp.jl @@ -201,12 +201,48 @@ if sizeof(Int64) == sizeof(Clong) end convert(::Type{Int128}, x::BigInt) = copysign(UInt128(abs(x))%Int128,x) -function convert(::Type{Float64}, n::BigInt) - # TODO: this should round to nearest but instead rounds to zero + +function call(::Type{Float64}, n::BigInt, ::RoundingMode{:ToZero}) ccall((:__gmpz_get_d, :libgmp), Float64, (Ptr{BigInt},), &n) end -convert(::Type{Float32}, n::BigInt) = Float32(Float64(n)) -convert(::Type{Float16}, n::BigInt) = Float16(Float64(n)) + +function call{T<:Union(Float16,Float32)}(::Type{T}, n::BigInt, ::RoundingMode{:ToZero}) + T(Float64(n,RoundToZero),RoundToZero) +end + +function call{T<:CdoubleMax}(::Type{T}, n::BigInt, ::RoundingMode{:Down}) + x = T(n,RoundToZero) + x > n ? prevfloat(x) : x +end +function call{T<:CdoubleMax}(::Type{T}, n::BigInt, ::RoundingMode{:Up}) + x = T(n,RoundToZero) + x < n ? nextfloat(x) : x +end +function call{T<:CdoubleMax}(::Type{T}, n::BigInt, ::RoundingMode{:Nearest}) + x = T(n,RoundToZero) + if maxintfloat(T) <= abs(x) < T(Inf) + r = n-BigInt(x) + h = eps(x)/2 + if iseven(reinterpret(Unsigned,x)) # check if last bit is odd/even + if r < -h + return prevfloat(x) + elseif r > h + return nextfloat(x) + end + else + if r <= -h + return prevfloat(x) + elseif r >= h + return nextfloat(x) + end + end + end + x +end + +convert(::Type{Float64}, n::BigInt) = Float64(n,RoundNearest) +convert(::Type{Float32}, n::BigInt) = Float32(n,RoundNearest) +convert(::Type{Float16}, n::BigInt) = Float16(n,RoundNearest) rem(x::BigInt, ::Type{Bool}) = ((x&1)!=0) @@ -216,6 +252,7 @@ function rem{T<:Integer}(n::BigInt, ::Type{T}) convert(T, (n-lo) & (widen(hi)-widen(lo)) + lo) end + promote_rule{T<:Integer}(::Type{BigInt}, ::Type{T}) = BigInt # serialization diff --git a/test/numbers.jl b/test/numbers.jl index a55230465834f..3169ae585cdc9 100644 --- a/test/numbers.jl +++ b/test/numbers.jl @@ -926,6 +926,18 @@ end @test !(Float32(pi,RoundDown) > pi) @test !(Float32(pi,RoundUp) < pi) +# issue #6365 +for T in (Float32, Float64) + for i = 9007199254740992:9007199254740996 + @test T(i) == T(BigFloat(i)) + @test T(-i) == T(BigFloat(-i)) + for r in (RoundNearest,RoundUp,RoundDown,RoundToZero) + @test T(i,r) == T(BigFloat(i),r) + @test T(-i,r) == T(BigFloat(-i),r) + end + end +end + @test prevfloat(big(pi)) < pi @test nextfloat(big(pi)) > pi @test !(prevfloat(big(pi)) > pi)