From f40987c50ea2c9476162430f8663be4531548766 Mon Sep 17 00:00:00 2001 From: Neven Sajko Date: Wed, 26 Jul 2023 06:37:50 +0200 Subject: [PATCH] Base.MPFR: don't `ccall` for special value predicates 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 (#50642) and performance, so this PR seems like the obvious prerequisite for being able to use the Julian predicates like `iszero` without calling libmpfr. --- base/mpfr.jl | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/base/mpfr.jl b/base/mpfr.jl index 2e03018f7669f7..06ec96a29dd863 100644 --- a/base/mpfr.jl +++ b/base/mpfr.jl @@ -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 @@ -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 @@ -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))