diff --git a/NEWS.md b/NEWS.md index da8e3aff75dfb..125651c6afcfe 100644 --- a/NEWS.md +++ b/NEWS.md @@ -261,6 +261,8 @@ This section lists changes that do not have deprecation warnings. Library improvements -------------------- + * `Irrational` is now a subtype of `AbstractIrrational` ([#24245]). + * The function `chop` now accepts two arguments `head` and `tail` allowing to specify number of characters to remove from the head and tail of the string ([#24126]). diff --git a/base/exports.jl b/base/exports.jl index 32adfd2188e11..0bb91aedb085b 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -23,6 +23,7 @@ export # Types AbstractChannel, + AbstractIrrational, AbstractMatrix, AbstractRange, AbstractSet, diff --git a/base/irrationals.jl b/base/irrationals.jl index 4e106bc54987b..dd6334223331e 100644 --- a/base/irrationals.jl +++ b/base/irrationals.jl @@ -3,24 +3,32 @@ ## general machinery for irrational mathematical constants """ - Irrational <: Real + AbstractIrrational <: Real -Irrational number type. +Number type representing an exact irrational value. """ -struct Irrational{sym} <: Real end +abstract type AbstractIrrational <: Real end + +""" + Irrational{sym} <: AbstractIrrational + +Number type representing an exact irrational value denoted by the +symbol `sym`. +""" +struct Irrational{sym} <: AbstractIrrational end show(io::IO, x::Irrational{sym}) where {sym} = print(io, "$sym = $(string(float(x))[1:15])...") -promote_rule(::Type{<:Irrational}, ::Type{Float16}) = Float16 -promote_rule(::Type{<:Irrational}, ::Type{Float32}) = Float32 -promote_rule(::Type{<:Irrational}, ::Type{<:Irrational}) = Float64 -promote_rule(::Type{<:Irrational}, ::Type{T}) where {T<:Number} = promote_type(Float64, T) +promote_rule(::Type{<:AbstractIrrational}, ::Type{Float16}) = Float16 +promote_rule(::Type{<:AbstractIrrational}, ::Type{Float32}) = Float32 +promote_rule(::Type{<:AbstractIrrational}, ::Type{<:AbstractIrrational}) = Float64 +promote_rule(::Type{<:AbstractIrrational}, ::Type{T}) where {T<:Number} = promote_type(Float64, T) -convert(::Type{AbstractFloat}, x::Irrational) = Float64(x) -convert(::Type{Float16}, x::Irrational) = Float16(Float32(x)) -convert(::Type{Complex{T}}, x::Irrational) where {T<:Real} = convert(Complex{T}, convert(T,x)) +convert(::Type{AbstractFloat}, x::AbstractIrrational) = Float64(x) +convert(::Type{Float16}, x::AbstractIrrational) = Float16(Float32(x)) +convert(::Type{Complex{T}}, x::AbstractIrrational) where {T<:Real} = convert(Complex{T}, convert(T,x)) -@pure function convert(::Type{Rational{T}}, x::Irrational) where T<:Integer +@pure function convert(::Type{Rational{T}}, x::AbstractIrrational) where T<:Integer o = precision(BigFloat) p = 256 while true @@ -34,50 +42,50 @@ convert(::Type{Complex{T}}, x::Irrational) where {T<:Real} = convert(Complex{T}, p += 32 end end -convert(::Type{Rational{BigInt}}, x::Irrational) = throw(ArgumentError("Cannot convert an Irrational to a Rational{BigInt}: use rationalize(Rational{BigInt}, x) instead")) +convert(::Type{Rational{BigInt}}, x::AbstractIrrational) = throw(ArgumentError("Cannot convert an AbstractIrrational to a Rational{BigInt}: use rationalize(Rational{BigInt}, x) instead")) -@pure function (t::Type{T})(x::Irrational, r::RoundingMode) where T<:Union{Float32,Float64} +@pure function (t::Type{T})(x::AbstractIrrational, r::RoundingMode) where T<:Union{Float32,Float64} setprecision(BigFloat, 256) do T(BigFloat(x), r) end end -float(::Type{<:Irrational}) = Float64 +float(::Type{<:AbstractIrrational}) = Float64 ==(::Irrational{s}, ::Irrational{s}) where {s} = true -==(::Irrational, ::Irrational) = false +==(::AbstractIrrational, ::AbstractIrrational) = false # Irrationals, by definition, can't have a finite representation equal them exactly -==(x::Irrational, y::Real) = false -==(x::Real, y::Irrational) = false +==(x::AbstractIrrational, y::Real) = false +==(x::Real, y::AbstractIrrational) = false # Irrational vs AbstractFloat -<(x::Irrational, y::Float64) = Float64(x,RoundUp) <= y -<(x::Float64, y::Irrational) = x <= Float64(y,RoundDown) -<(x::Irrational, y::Float32) = Float32(x,RoundUp) <= y -<(x::Float32, y::Irrational) = x <= Float32(y,RoundDown) -<(x::Irrational, y::Float16) = Float32(x,RoundUp) <= y -<(x::Float16, y::Irrational) = x <= Float32(y,RoundDown) -<(x::Irrational, y::BigFloat) = setprecision(precision(y)+32) do +<(x::AbstractIrrational, y::Float64) = Float64(x,RoundUp) <= y +<(x::Float64, y::AbstractIrrational) = x <= Float64(y,RoundDown) +<(x::AbstractIrrational, y::Float32) = Float32(x,RoundUp) <= y +<(x::Float32, y::AbstractIrrational) = x <= Float32(y,RoundDown) +<(x::AbstractIrrational, y::Float16) = Float32(x,RoundUp) <= y +<(x::Float16, y::AbstractIrrational) = x <= Float32(y,RoundDown) +<(x::AbstractIrrational, y::BigFloat) = setprecision(precision(y)+32) do big(x) < y end -<(x::BigFloat, y::Irrational) = setprecision(precision(x)+32) do +<(x::BigFloat, y::AbstractIrrational) = setprecision(precision(x)+32) do x < big(y) end -<=(x::Irrational, y::AbstractFloat) = x < y -<=(x::AbstractFloat, y::Irrational) = x < y +<=(x::AbstractIrrational, y::AbstractFloat) = x < y +<=(x::AbstractFloat, y::AbstractIrrational) = x < y # Irrational vs Rational -@pure function rationalize(::Type{T}, x::Irrational; tol::Real=0) where T +@pure function rationalize(::Type{T}, x::AbstractIrrational; tol::Real=0) where T return rationalize(T, big(x), tol=tol) end -@pure function lessrational(rx::Rational{<:Integer}, x::Irrational) +@pure function lessrational(rx::Rational{<:Integer}, x::AbstractIrrational) # an @pure version of `<` for determining if the rationalization of # an irrational number required rounding up or down return rx < big(x) end -function <(x::Irrational, y::Rational{T}) where T +function <(x::AbstractIrrational, y::Rational{T}) where T T <: Unsigned && x < 0.0 && return true rx = rationalize(T, x) if lessrational(rx, x) @@ -86,7 +94,7 @@ function <(x::Irrational, y::Rational{T}) where T return rx <= y end end -function <(x::Rational{T}, y::Irrational) where T +function <(x::Rational{T}, y::AbstractIrrational) where T T <: Unsigned && y < 0.0 && return false ry = rationalize(T, y) if lessrational(ry, y) @@ -95,24 +103,24 @@ function <(x::Rational{T}, y::Irrational) where T return x < ry end end -<(x::Irrational, y::Rational{BigInt}) = big(x) < y -<(x::Rational{BigInt}, y::Irrational) = x < big(y) +<(x::AbstractIrrational, y::Rational{BigInt}) = big(x) < y +<(x::Rational{BigInt}, y::AbstractIrrational) = x < big(y) -<=(x::Irrational, y::Rational) = x < y -<=(x::Rational, y::Irrational) = x < y +<=(x::AbstractIrrational, y::Rational) = x < y +<=(x::Rational, y::AbstractIrrational) = x < y -isfinite(::Irrational) = true -isinteger(::Irrational) = false -iszero(::Irrational) = false -isone(::Irrational) = false +isfinite(::AbstractIrrational) = true +isinteger(::AbstractIrrational) = false +iszero(::AbstractIrrational) = false +isone(::AbstractIrrational) = false hash(x::Irrational, h::UInt) = 3*object_id(x) - h --(x::Irrational) = -Float64(x) +-(x::AbstractIrrational) = -Float64(x) for op in Symbol[:+, :-, :*, :/, :^] - @eval $op(x::Irrational, y::Irrational) = $op(Float64(x),Float64(y)) + @eval $op(x::AbstractIrrational, y::AbstractIrrational) = $op(Float64(x),Float64(y)) end -*(x::Bool, y::Irrational) = ifelse(x, Float64(y), 0.0) +*(x::Bool, y::AbstractIrrational) = ifelse(x, Float64(y), 0.0) macro irrational(sym, val, def) esym = esc(sym) @@ -138,11 +146,11 @@ macro irrational(sym, val, def) end end -big(x::Irrational) = convert(BigFloat,x) -big(::Type{<:Irrational}) = BigFloat +big(x::AbstractIrrational) = convert(BigFloat,x) +big(::Type{<:AbstractIrrational}) = BigFloat # align along = for nice Array printing -function alignment(io::IO, x::Irrational) +function alignment(io::IO, x::AbstractIrrational) m = match(r"^(.*?)(=.*)$", sprint(0, showcompact, x, env=io)) m === nothing ? (length(sprint(0, showcompact, x, env=io)), 0) : (length(m.captures[1]), length(m.captures[2])) diff --git a/base/mathconstants.jl b/base/mathconstants.jl index 68822ff3a4706..1dfe7e584260f 100644 --- a/base/mathconstants.jl +++ b/base/mathconstants.jl @@ -82,7 +82,7 @@ catalan = 0.9159655941772... catalan # loop over types to prevent ambiguities for ^(::Number, x) -for T in (Irrational, Rational, Integer, Number) +for T in (AbstractIrrational, Rational, Integer, Number) Base.:^(::Irrational{:ℯ}, x::T) = exp(x) end diff --git a/doc/src/stdlib/numbers.md b/doc/src/stdlib/numbers.md index 836224264ccd9..9ed0821042869 100644 --- a/doc/src/stdlib/numbers.md +++ b/doc/src/stdlib/numbers.md @@ -11,6 +11,7 @@ Core.AbstractFloat Core.Integer Core.Signed Core.Unsigned +Base.AbstractIrrational ``` ### Concrete number types