Skip to content

Commit

Permalink
Base.MPFR: don't ccall for special value predicates
Browse files Browse the repository at this point in the history
MPFR determines special values according to sentinel values of the
exponent field. Although these constants are not documented (they're
defined in MPFR's `src/mpfr-impl.h`), they're now already used in
`Base.MPFR` for converting IEEE 754 to `BigFloat`, so I guess it makes
sense to avoid the `ccall` overhead for predicates like `iszero` and
`isnan`, too.

The context here is that I'm working on generic IEEE 754-`BigFloat`
conversion implementations that would work without using MPFR and
improve correctness (JuliaLang#50642) and performance, so this PR seems like the
obvious prerequisite for being able to use the Julian predicates like
`iszero` without calling libmpfr.
  • Loading branch information
nsajko committed Jul 26, 2023
1 parent 7ca0f0d commit f40987c
Showing 1 changed file with 12 additions and 6 deletions.
18 changes: 12 additions & 6 deletions base/mpfr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,12 @@ for (fJ, fC) in ((:si,:Clong), (:ui,:Culong))
end
end

# Warning: the constants are MPFR implementation details from
# `src/mpfr-impl.h`, search for `MPFR_EXP_ZERO`.
mpfr_special_exponent(::Val{:zero}) = typemin(Clong) + true
mpfr_special_exponent(::Val{:nan}) = mpfr_special_exponent(Val(:zero)) + true
mpfr_special_exponent(::Val{:inf}) = mpfr_special_exponent(Val(:nan)) + true

function BigFloat(x::Float64, r::MPFRRoundingMode=ROUNDING_MODE[]; precision::Integer=DEFAULT_PRECISION[])
z = BigFloat(;precision)
# punt on the hard case where we might have to deal with rounding
Expand All @@ -234,11 +240,11 @@ function BigFloat(x::Float64, r::MPFRRoundingMode=ROUNDING_MODE[]; precision::In
z.sign = 1-2*signbit(x)
if iszero(x) || !isfinite(x)
if isinf(x)
z.exp = Clong(2) - typemax(Clong)
z.exp = mpfr_special_exponent(Val(:inf))
elseif isnan(x)
z.exp = Clong(1) - typemax(Clong)
z.exp = mpfr_special_exponent(Val(:nan))
else
z.exp = - typemax(Clong)
z.exp = mpfr_special_exponent(Val(:zero))
end
return z
end
Expand Down Expand Up @@ -976,16 +982,16 @@ for (f,R) in ((:roundeven, :Nearest),
end

function isinf(x::BigFloat)
return ccall((:mpfr_inf_p, libmpfr), Int32, (Ref{BigFloat},), x) != 0
return x.exp == mpfr_special_exponent(Val(:inf))
end

function isnan(x::BigFloat)
return ccall((:mpfr_nan_p, libmpfr), Int32, (Ref{BigFloat},), x) != 0
return x.exp == mpfr_special_exponent(Val(:nan))
end

isfinite(x::BigFloat) = !isinf(x) && !isnan(x)

iszero(x::BigFloat) = x == Clong(0)
iszero(x::BigFloat) = x.exp == mpfr_special_exponent(Val(:zero))
isone(x::BigFloat) = x == Clong(1)

@eval typemax(::Type{BigFloat}) = $(BigFloat(Inf))
Expand Down

0 comments on commit f40987c

Please sign in to comment.