Skip to content

Commit

Permalink
make Irrational <: AbstractIrrational (#24245)
Browse files Browse the repository at this point in the history
  • Loading branch information
stevengj authored and JeffBezanson committed Oct 26, 2017
1 parent dbb3cf0 commit 547c1aa
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 46 deletions.
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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]).

Expand Down
1 change: 1 addition & 0 deletions base/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export

# Types
AbstractChannel,
AbstractIrrational,
AbstractMatrix,
AbstractRange,
AbstractSet,
Expand Down
98 changes: 53 additions & 45 deletions base/irrationals.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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]))
Expand Down
2 changes: 1 addition & 1 deletion base/mathconstants.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
1 change: 1 addition & 0 deletions doc/src/stdlib/numbers.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Core.AbstractFloat
Core.Integer
Core.Signed
Core.Unsigned
Base.AbstractIrrational
```

### Concrete number types
Expand Down

0 comments on commit 547c1aa

Please sign in to comment.