Skip to content

Commit

Permalink
preserve sign of NaN in conversions to and from BigFloat (#25378)
Browse files Browse the repository at this point in the history
  • Loading branch information
JeffBezanson authored Jan 5, 2018
1 parent e8c7469 commit b8b4fb3
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 7 deletions.
27 changes: 20 additions & 7 deletions base/mpfr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ widen(::Type{BigFloat}) = BigFloat
BigFloat(x::BigFloat) = x

# convert to BigFloat
for (fJ, fC) in ((:si,:Clong), (:ui,:Culong), (:d,:Float64))
for (fJ, fC) in ((:si,:Clong), (:ui,:Culong))
@eval begin
function BigFloat(x::($fC))
z = BigFloat()
Expand All @@ -107,6 +107,16 @@ for (fJ, fC) in ((:si,:Clong), (:ui,:Culong), (:d,:Float64))
end
end

function BigFloat(x::Float64)
z = BigFloat()
ccall((:mpfr_set_d, :libmpfr), Int32, (Ref{BigFloat}, Float64, Int32), z, x, ROUNDING_MODE[])
if isnan(x) && signbit(x) != signbit(z)
# for some reason doing mpfr_neg in-place doesn't work here
return -z
end
return z
end

function BigFloat(x::BigInt)
z = BigFloat()
ccall((:mpfr_set_z, :libmpfr), Int32, (Ref{BigFloat}, Ref{BigInt}, Int32), z, x, ROUNDING_MODE[])
Expand Down Expand Up @@ -247,19 +257,22 @@ function (::Type{T})(x::BigFloat) where T<:Integer
end

## BigFloat -> AbstractFloat

_cpynansgn(x::AbstractFloat, y::BigFloat) = isnan(x) && signbit(x) != signbit(y) ? -x : x

Float64(x::BigFloat) =
ccall((:mpfr_get_d,:libmpfr), Float64, (Ref{BigFloat}, Int32), x, ROUNDING_MODE[])
_cpynansgn(ccall((:mpfr_get_d,:libmpfr), Float64, (Ref{BigFloat}, Int32), x, ROUNDING_MODE[]), x)
Float32(x::BigFloat) =
ccall((:mpfr_get_flt,:libmpfr), Float32, (Ref{BigFloat}, Int32), x, ROUNDING_MODE[])
_cpynansgn(ccall((:mpfr_get_flt,:libmpfr), Float32, (Ref{BigFloat}, Int32), x, ROUNDING_MODE[]), x)
# TODO: avoid double rounding
Float16(x::BigFloat) = convert(Float16, convert(Float32, x))
Float16(x::BigFloat) = Float16(Float32(x))

Float64(x::BigFloat, r::RoundingMode) =
ccall((:mpfr_get_d,:libmpfr), Float64, (Ref{BigFloat}, Int32), x, to_mpfr(r))
_cpynansgn(ccall((:mpfr_get_d,:libmpfr), Float64, (Ref{BigFloat}, Int32), x, to_mpfr(r)), x)
Float32(x::BigFloat, r::RoundingMode) =
ccall((:mpfr_get_flt,:libmpfr), Float32, (Ref{BigFloat}, Int32), x, to_mpfr(r))
_cpynansgn(ccall((:mpfr_get_flt,:libmpfr), Float32, (Ref{BigFloat}, Int32), x, to_mpfr(r)), x)
# TODO: avoid double rounding
Float16(x::BigFloat, r::RoundingMode) = convert(Float16, Float32(x, r))
Float16(x::BigFloat, r::RoundingMode) = Float16(Float32(x, r))

promote_rule(::Type{BigFloat}, ::Type{<:Real}) = BigFloat
promote_rule(::Type{BigInt}, ::Type{<:AbstractFloat}) = BigFloat
Expand Down
7 changes: 7 additions & 0 deletions test/mpfr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,7 @@ end
y = BigFloat(-1)
@test copysign(x, y) == y
@test copysign(y, x) == x
@test copysign(1.0, BigFloat(NaN)) == 1.0
end
@testset "isfinite / isinf / isnan" begin
x = BigFloat(Inf)
Expand Down Expand Up @@ -380,6 +381,9 @@ end
@test typeof(convert(BigFloat, parse(BigInt,"9223372036854775808"))) == BigFloat
@test convert(AbstractFloat, parse(BigInt,"9223372036854775808")) == parse(BigFloat,"9223372036854775808")
@test typeof(convert(AbstractFloat, parse(BigInt,"9223372036854775808"))) == BigFloat

@test signbit(BigFloat(NaN)) == 0
@test signbit(BigFloat(-NaN)) == 1
end
@testset "convert from BigFloat" begin
@test convert(Float64, BigFloat(0.5)) == 0.5
Expand All @@ -388,6 +392,9 @@ end
@test convert(Bool, BigFloat(0.0)) == false
@test convert(Bool, BigFloat(1.0)) == true
@test_throws InexactError convert(Bool, BigFloat(0.1))

@test signbit(Float64(BigFloat(NaN))) == 0
@test signbit(Float64(-BigFloat(NaN))) == 1
end
@testset "exponent, frexp, significand" begin
x = BigFloat(0)
Expand Down

0 comments on commit b8b4fb3

Please sign in to comment.