From b8b4fb3b3e79d2cd65f72941919c33bb8bd7a6ab Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Fri, 5 Jan 2018 14:21:59 -0500 Subject: [PATCH] preserve sign of NaN in conversions to and from BigFloat (#25378) --- base/mpfr.jl | 27 ++++++++++++++++++++------- test/mpfr.jl | 7 +++++++ 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/base/mpfr.jl b/base/mpfr.jl index cf54f930ef252..2338581d14902 100644 --- a/base/mpfr.jl +++ b/base/mpfr.jl @@ -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() @@ -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[]) @@ -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 diff --git a/test/mpfr.jl b/test/mpfr.jl index 7511676c5a16b..cd90a75165346 100644 --- a/test/mpfr.jl +++ b/test/mpfr.jl @@ -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) @@ -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 @@ -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)