From d60837f29e861fad4afe6c29dba788e44b627bf4 Mon Sep 17 00:00:00 2001 From: Neven Sajko Date: Thu, 10 Oct 2024 16:10:33 +0200 Subject: [PATCH] irrationals: restrict assume effects annotations to known types (#55886) Other changes: * replace `:total` with the less powerful `:foldable` * add an `<:Integer` dispatch constraint on the `rationalize` method, closes #55872 * replace `Rational{<:Integer}` with just `Rational`, they're equal Other issues, related to `BigFloat` precision, are still present in irrationals.jl, to be fixed by followup PRs, including #55853. Fixes #55874 --- base/irrationals.jl | 22 ++++++++++++++-------- base/mathconstants.jl | 20 ++++++++++++++++++++ 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/base/irrationals.jl b/base/irrationals.jl index b3073c503238a..c51b66045723f 100644 --- a/base/irrationals.jl +++ b/base/irrationals.jl @@ -51,8 +51,7 @@ AbstractFloat(x::AbstractIrrational) = Float64(x)::Float64 Float16(x::AbstractIrrational) = Float16(Float32(x)::Float32) Complex{T}(x::AbstractIrrational) where {T<:Real} = Complex{T}(T(x)) -# XXX this may change `DEFAULT_PRECISION`, thus not effect free -@assume_effects :total function Rational{T}(x::AbstractIrrational) where T<:Integer +function _irrational_to_rational(::Type{T}, x::AbstractIrrational) where T<:Integer o = precision(BigFloat) p = 256 while true @@ -66,13 +65,16 @@ Complex{T}(x::AbstractIrrational) where {T<:Real} = Complex{T}(T(x)) p += 32 end end -Rational{BigInt}(x::AbstractIrrational) = throw(ArgumentError("Cannot convert an AbstractIrrational to a Rational{BigInt}: use rationalize(BigInt, x) instead")) +Rational{T}(x::AbstractIrrational) where {T<:Integer} = _irrational_to_rational(T, x) +_throw_argument_error_irrational_to_rational_bigint() = throw(ArgumentError("Cannot convert an AbstractIrrational to a Rational{BigInt}: use rationalize(BigInt, x) instead")) +Rational{BigInt}(::AbstractIrrational) = _throw_argument_error_irrational_to_rational_bigint() -@assume_effects :total function (t::Type{T})(x::AbstractIrrational, r::RoundingMode) where T<:Union{Float32,Float64} +function _irrational_to_float(::Type{T}, x::AbstractIrrational, r::RoundingMode) where T<:Union{Float32,Float64} setprecision(BigFloat, 256) do T(BigFloat(x)::BigFloat, r) end end +(::Type{T})(x::AbstractIrrational, r::RoundingMode) where {T<:Union{Float32,Float64}} = _irrational_to_float(T, x, r) float(::Type{<:AbstractIrrational}) = Float64 @@ -110,14 +112,18 @@ end <=(x::AbstractFloat, y::AbstractIrrational) = x < y # Irrational vs Rational -@assume_effects :total function rationalize(::Type{T}, x::AbstractIrrational; tol::Real=0) where T +function _rationalize_irrational(::Type{T}, x::AbstractIrrational, tol::Real) where {T<:Integer} return rationalize(T, big(x), tol=tol) end -@assume_effects :total function lessrational(rx::Rational{<:Integer}, x::AbstractIrrational) - # an @assume_effects :total version of `<` for determining if the rationalization of - # an irrational number required rounding up or down +function rationalize(::Type{T}, x::AbstractIrrational; tol::Real=0) where {T<:Integer} + return _rationalize_irrational(T, x, tol) +end +function _lessrational(rx::Rational, x::AbstractIrrational) return rx < big(x) end +function lessrational(rx::Rational, x::AbstractIrrational) + return _lessrational(rx, x) +end function <(x::AbstractIrrational, y::Rational{T}) where T T <: Unsigned && x < 0.0 && return true rx = rationalize(T, x) diff --git a/base/mathconstants.jl b/base/mathconstants.jl index 4bb8c409acf00..de6b98cea634d 100644 --- a/base/mathconstants.jl +++ b/base/mathconstants.jl @@ -16,6 +16,26 @@ Base.@irrational γ euler Base.@irrational φ (1+sqrt(big(5)))/2 Base.@irrational catalan catalan +const _KnownIrrational = Union{ + typeof(π), typeof(ℯ), typeof(γ), typeof(φ), typeof(catalan) +} + +function Rational{BigInt}(::_KnownIrrational) + Base._throw_argument_error_irrational_to_rational_bigint() +end +Base.@assume_effects :foldable function Rational{T}(x::_KnownIrrational) where {T<:Integer} + Base._irrational_to_rational(T, x) +end +Base.@assume_effects :foldable function (::Type{T})(x::_KnownIrrational, r::RoundingMode) where {T<:Union{Float32,Float64}} + Base._irrational_to_float(T, x, r) +end +Base.@assume_effects :foldable function rationalize(::Type{T}, x::_KnownIrrational; tol::Real=0) where {T<:Integer} + Base._rationalize_irrational(T, x, tol) +end +Base.@assume_effects :foldable function Base.lessrational(rx::Rational, x::_KnownIrrational) + Base._lessrational(rx, x) +end + # aliases """ π