diff --git a/NEWS.md b/NEWS.md index fd7ab26cae8d4a..a0d1ba82b58a7d 100644 --- a/NEWS.md +++ b/NEWS.md @@ -275,6 +275,8 @@ Library improvements * Optional `log` and `log1p` functions implemented in pure Julia (experimental) ([#10008]). + * The `MathCont` type has been renamed `Irrational`. + * Random numbers * Streamlined random number generation APIs [#8246]. diff --git a/base/constants.jl b/base/constants.jl deleted file mode 100644 index 3a97fc779e8831..00000000000000 --- a/base/constants.jl +++ /dev/null @@ -1,137 +0,0 @@ -# This file is a part of Julia. License is MIT: http://julialang.org/license - -## general machinery for mathematical constants - -immutable MathConst{sym} <: Real end - -show{sym}(io::IO, x::MathConst{sym}) = print(io, "$sym = $(string(float(x))[1:15])...") - -promote_rule{s}(::Type{MathConst{s}}, ::Type{Float32}) = Float32 -promote_rule{s,t}(::Type{MathConst{s}}, ::Type{MathConst{t}}) = Float64 -promote_rule{s,T<:Number}(::Type{MathConst{s}}, ::Type{T}) = promote_type(Float64,T) - -convert(::Type{FloatingPoint}, x::MathConst) = Float64(x) -convert(::Type{Float16}, x::MathConst) = Float16(Float32(x)) -convert{T<:Real}(::Type{Complex{T}}, x::MathConst) = convert(Complex{T}, convert(T,x)) -convert{T<:Integer}(::Type{Rational{T}}, x::MathConst) = convert(Rational{T}, Float64(x)) - -@generated function call{T<:Union{Float32,Float64},s}(t::Type{T},c::MathConst{s},r::RoundingMode) - f = T(big(c()),r()) - :($f) -end - -=={s}(::MathConst{s}, ::MathConst{s}) = true -==(::MathConst, ::MathConst) = false - -# MathConsts are irrational, so unequal to everything else -==(x::MathConst, y::Real) = false -==(x::Real, y::MathConst) = false - -# MathConst vs FloatingPoint -<(x::MathConst, y::Float64) = Float64(x,RoundUp) <= y -<(x::Float64, y::MathConst) = x <= Float64(y,RoundDown) -<(x::MathConst, y::Float32) = Float32(x,RoundUp) <= y -<(x::Float32, y::MathConst) = x <= Float32(y,RoundDown) -<(x::MathConst, y::Float16) = Float32(x,RoundUp) <= y -<(x::Float16, y::MathConst) = x <= Float32(y,RoundDown) -<(x::MathConst, y::BigFloat) = with_bigfloat_precision(precision(y)+32) do - big(x) < y -end -<(x::BigFloat, y::MathConst) = with_bigfloat_precision(precision(x)+32) do - x < big(y) -end - -<=(x::MathConst,y::FloatingPoint) = x < y -<=(x::FloatingPoint,y::MathConst) = x < y - -# MathConst vs Rational -@generated function <{T}(x::MathConst, y::Rational{T}) - bx = big(x()) - bx < 0 && T <: Unsigned && return true - rx = rationalize(T,bx,tol=0) - rx < bx ? :($rx < y) : :($rx <= y) -end -@generated function <{T}(x::Rational{T}, y::MathConst) - by = big(y()) - by < 0 && T <: Unsigned && return false - ry = rationalize(T,by,tol=0) - ry < by ? :(x <= $ry) : :(x < $ry) -end -<(x::MathConst, y::Rational{BigInt}) = big(x) < y -<(x::Rational{BigInt}, y::MathConst) = x < big(y) - -<=(x::MathConst,y::Rational) = x < y -<=(x::Rational,y::MathConst) = x < y - - -hash(x::MathConst, h::UInt) = 3*object_id(x) - h - --(x::MathConst) = -Float64(x) -for op in Symbol[:+, :-, :*, :/, :^] - @eval $op(x::MathConst, y::MathConst) = $op(Float64(x),Float64(y)) -end - -macro math_const(sym, val, def) - esym = esc(sym) - qsym = esc(Expr(:quote, sym)) - bigconvert = isa(def,Symbol) ? quote - function Base.convert(::Type{BigFloat}, ::MathConst{$qsym}) - c = BigFloat() - ccall(($(string("mpfr_const_", def)), :libmpfr), - Cint, (Ptr{BigFloat}, Int32), - &c, MPFR.ROUNDING_MODE[end]) - return c - end - end : quote - Base.convert(::Type{BigFloat}, ::MathConst{$qsym}) = $(esc(def)) - end - quote - const $esym = MathConst{$qsym}() - $bigconvert - Base.convert(::Type{Float64}, ::MathConst{$qsym}) = $val - Base.convert(::Type{Float32}, ::MathConst{$qsym}) = $(Float32(val)) - @assert isa(big($esym), BigFloat) - @assert Float64($esym) == Float64(big($esym)) - @assert Float32($esym) == Float32(big($esym)) - end -end - -big(x::MathConst) = convert(BigFloat,x) - -## specific mathematical constants - -@math_const π 3.14159265358979323846 pi -@math_const e 2.71828182845904523536 exp(big(1)) -@math_const γ 0.57721566490153286061 euler -@math_const catalan 0.91596559417721901505 catalan -@math_const φ 1.61803398874989484820 (1+sqrt(big(5)))/2 - -# aliases -const pi = π -const eu = e -const eulergamma = γ -const golden = φ - -# special behaviors - -# use exp for e^x or e.^x, as in -# ^(::MathConst{:e}, x::Number) = exp(x) -# .^(::MathConst{:e}, x) = exp(x) -# but need to loop over types to prevent ambiguity with generic rules for ^(::Number, x) etc. -for T in (MathConst, Rational, Integer, Number) - ^(::MathConst{:e}, x::T) = exp(x) -end -for T in (Range, BitArray, SparseMatrixCSC, StridedArray, AbstractArray) - .^(::MathConst{:e}, x::T) = exp(x) -end -^(::MathConst{:e}, x::AbstractMatrix) = expm(x) - -log(::MathConst{:e}) = 1 # use 1 to correctly promote expressions like log(x)/log(e) -log(::MathConst{:e}, x) = log(x) - -#Align along = for nice Array printing -function alignment(x::MathConst) - m = match(r"^(.*?)(=.*)$", sprint(showcompact_lim, x)) - m == nothing ? (length(sprint(showcompact_lim, x)), 0) : - (length(m.captures[1]), length(m.captures[2])) -end diff --git a/base/deprecated.jl b/base/deprecated.jl index 42d8f12978997e..ccd6c1c9904aff 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -535,3 +535,6 @@ end const UnionType = Union export UnionType + +const MathConst = Irrational +export MathConst diff --git a/base/exports.jl b/base/exports.jl index f2e774b1b8b717..2971b68c4194a4 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -70,7 +70,7 @@ export LinSpace, LocalProcess, LowerTriangular, - MathConst, + Irrational, Matrix, MergeSort, Nullable, diff --git a/base/irrationals.jl b/base/irrationals.jl new file mode 100644 index 00000000000000..df3bbe9b5471ca --- /dev/null +++ b/base/irrationals.jl @@ -0,0 +1,137 @@ +# This file is a part of Julia. License is MIT: http://julialang.org/license + +## general machinery for irrational mathematical constants + +immutable Irrational{sym} <: Real end + +show{sym}(io::IO, x::Irrational{sym}) = print(io, "$sym = $(string(float(x))[1:15])...") + +promote_rule{s}(::Type{Irrational{s}}, ::Type{Float32}) = Float32 +promote_rule{s,t}(::Type{Irrational{s}}, ::Type{Irrational{t}}) = Float64 +promote_rule{s,T<:Number}(::Type{Irrational{s}}, ::Type{T}) = promote_type(Float64,T) + +convert(::Type{FloatingPoint}, x::Irrational) = Float64(x) +convert(::Type{Float16}, x::Irrational) = Float16(Float32(x)) +convert{T<:Real}(::Type{Complex{T}}, x::Irrational) = convert(Complex{T}, convert(T,x)) +convert{T<:Integer}(::Type{Rational{T}}, x::Irrational) = convert(Rational{T}, Float64(x)) + +@generated function call{T<:Union{Float32,Float64},s}(t::Type{T},c::Irrational{s},r::RoundingMode) + f = T(big(c()),r()) + :($f) +end + +=={s}(::Irrational{s}, ::Irrational{s}) = true +==(::Irrational, ::Irrational) = false + +# MathConsts are irrational, so unequal to everything else +==(x::Irrational, y::Real) = false +==(x::Real, y::Irrational) = false + +# Irrational vs FloatingPoint +<(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) = with_bigfloat_precision(precision(y)+32) do + big(x) < y +end +<(x::BigFloat, y::Irrational) = with_bigfloat_precision(precision(x)+32) do + x < big(y) +end + +<=(x::Irrational,y::FloatingPoint) = x < y +<=(x::FloatingPoint,y::Irrational) = x < y + +# Irrational vs Rational +@generated function <{T}(x::Irrational, y::Rational{T}) + bx = big(x()) + bx < 0 && T <: Unsigned && return true + rx = rationalize(T,bx,tol=0) + rx < bx ? :($rx < y) : :($rx <= y) +end +@generated function <{T}(x::Rational{T}, y::Irrational) + by = big(y()) + by < 0 && T <: Unsigned && return false + ry = rationalize(T,by,tol=0) + ry < by ? :(x <= $ry) : :(x < $ry) +end +<(x::Irrational, y::Rational{BigInt}) = big(x) < y +<(x::Rational{BigInt}, y::Irrational) = x < big(y) + +<=(x::Irrational,y::Rational) = x < y +<=(x::Rational,y::Irrational) = x < y + + +hash(x::Irrational, h::UInt) = 3*object_id(x) - h + +-(x::Irrational) = -Float64(x) +for op in Symbol[:+, :-, :*, :/, :^] + @eval $op(x::Irrational, y::Irrational) = $op(Float64(x),Float64(y)) +end + +macro math_const(sym, val, def) + esym = esc(sym) + qsym = esc(Expr(:quote, sym)) + bigconvert = isa(def,Symbol) ? quote + function Base.convert(::Type{BigFloat}, ::Irrational{$qsym}) + c = BigFloat() + ccall(($(string("mpfr_const_", def)), :libmpfr), + Cint, (Ptr{BigFloat}, Int32), + &c, MPFR.ROUNDING_MODE[end]) + return c + end + end : quote + Base.convert(::Type{BigFloat}, ::Irrational{$qsym}) = $(esc(def)) + end + quote + const $esym = Irrational{$qsym}() + $bigconvert + Base.convert(::Type{Float64}, ::Irrational{$qsym}) = $val + Base.convert(::Type{Float32}, ::Irrational{$qsym}) = $(Float32(val)) + @assert isa(big($esym), BigFloat) + @assert Float64($esym) == Float64(big($esym)) + @assert Float32($esym) == Float32(big($esym)) + end +end + +big(x::Irrational) = convert(BigFloat,x) + +## specific mathematical constants + +@math_const π 3.14159265358979323846 pi +@math_const e 2.71828182845904523536 exp(big(1)) +@math_const γ 0.57721566490153286061 euler +@math_const catalan 0.91596559417721901505 catalan +@math_const φ 1.61803398874989484820 (1+sqrt(big(5)))/2 + +# aliases +const pi = π +const eu = e +const eulergamma = γ +const golden = φ + +# special behaviors + +# use exp for e^x or e.^x, as in +# ^(::Irrational{:e}, x::Number) = exp(x) +# .^(::Irrational{:e}, x) = exp(x) +# but need to loop over types to prevent ambiguity with generic rules for ^(::Number, x) etc. +for T in (Irrational, Rational, Integer, Number) + ^(::Irrational{:e}, x::T) = exp(x) +end +for T in (Range, BitArray, SparseMatrixCSC, StridedArray, AbstractArray) + .^(::Irrational{:e}, x::T) = exp(x) +end +^(::Irrational{:e}, x::AbstractMatrix) = expm(x) + +log(::Irrational{:e}) = 1 # use 1 to correctly promote expressions like log(x)/log(e) +log(::Irrational{:e}, x) = log(x) + +#Align along = for nice Array printing +function alignment(x::Irrational) + m = match(r"^(.*?)(=.*)$", sprint(showcompact_lim, x)) + m == nothing ? (length(sprint(showcompact_lim, x)), 0) : + (length(m.captures[1]), length(m.captures[2])) +end diff --git a/base/sysimg.jl b/base/sysimg.jl index 38a83674dc8eab..ba2b748a28030e 100644 --- a/base/sysimg.jl +++ b/base/sysimg.jl @@ -276,8 +276,8 @@ end include("sysinfo.jl") import .Sys.CPU_CORES -# mathematical constants -include("constants.jl") +# irrational mathematical constants +include("irrationals.jl") # Numerical integration include("quadgk.jl") diff --git a/contrib/BBEditTextWrangler-julia.plist b/contrib/BBEditTextWrangler-julia.plist index 4ec8af08e3bd4a..9755f658062e58 100644 --- a/contrib/BBEditTextWrangler-julia.plist +++ b/contrib/BBEditTextWrangler-julia.plist @@ -1207,7 +1207,7 @@ LoadError LocalProcess MIME - MathConst + Irrational Matrix MersenneTwister Meta diff --git a/contrib/julia.xml b/contrib/julia.xml index 1e3d57415d320a..aab0c7ce480159 100644 --- a/contrib/julia.xml +++ b/contrib/julia.xml @@ -139,7 +139,7 @@ IOStream LocalProcess LU - MathConst + Irrational Matrix NTuple Number diff --git a/doc/manual/methods.rst b/doc/manual/methods.rst index 8a412ef868b8c8..7ec126fea29d8a 100644 --- a/doc/manual/methods.rst +++ b/doc/manual/methods.rst @@ -267,7 +267,7 @@ Julia language. Core operations typically have dozens of methods:: +(a::Base.MPFR.BigFloat,b::Base.MPFR.BigFloat,c::Base.MPFR.BigFloat) at mpfr.jl:318 +(a::Base.MPFR.BigFloat,b::Base.MPFR.BigFloat,c::Base.MPFR.BigFloat,d::Base.MPFR.BigFloat) at mpfr.jl:324 +(a::Base.MPFR.BigFloat,b::Base.MPFR.BigFloat,c::Base.MPFR.BigFloat,d::Base.MPFR.BigFloat,e::Base.MPFR.BigFloat) at mpfr.jl:331 - +(x::MathConst{sym},y::MathConst{sym}) at constants.jl:71 + +(x::Irrational{sym},y::Irrational{sym}) at constants.jl:71 +{T<:Number}(x::T<:Number,y::T<:Number) at promotion.jl:205 +{T<:FloatingPoint}(x::Bool,y::T<:FloatingPoint) at bool.jl:43 +(x::Number,y::Number) at promotion.jl:167 diff --git a/test/numbers.jl b/test/numbers.jl index 3d3e79355b4327..7d93d2607aeda6 100644 --- a/test/numbers.jl +++ b/test/numbers.jl @@ -2408,7 +2408,7 @@ end @test bswap(reinterpret(Float32,0x0000c03f)) === 1.5f0 #isreal(x::Real) = true -for x in [1.23, 7, e, 4//5] #[FP, Int, MathConst, Rat] +for x in [1.23, 7, e, 4//5] #[FP, Int, Irrational, Rat] @test isreal(x) == true end @@ -2423,7 +2423,7 @@ for x in [subtypes(Complex); subtypes(Real)] end #getindex(x::Number) = x -for x in [1.23, 7, e, 4//5] #[FP, Int, MathConst, Rat] +for x in [1.23, 7, e, 4//5] #[FP, Int, Irrational, Rat] @test getindex(x) == x end