Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix tests and update with recent changes in Base #36

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "IrrationalConstants"
uuid = "92d709cd-6900-40b7-9082-c6be49f344b6"
authors = ["JuliaMath"]
version = "0.2.2"
version = "0.2.3"

[compat]
julia = "1"
Expand Down
72 changes: 46 additions & 26 deletions src/macro.jl
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,19 @@ if VERSION < v"1.2.0-DEV.337"
Base.inv(x::IrrationalConstant) = 1/x
end

# https://github.com/JuliaLang/julia/pull/50894
Base.typemin(::Type{T}) where {T<:IrrationalConstant} = T()
Base.typemax(::Type{T}) where {T<:IrrationalConstant} = T()

"""
@irrational sym val def [T]
@irrational(sym, val, def[, T])
@irrational sym [val] def [T]

Define an instance named `sym` of a new singleton type `T` representing an irrational constant as subtype of
`IrrationalConstants.IrrationalConstant <: AbstractIrrational`,
with arbitrary-precision definition in terms of `BigFloat`s given by the expression `def`.

Define a new singleton type `T` representing an irrational constant as subtype of
`IrrationalConstants.IrrationalConstant <: AbstractIrrational` with an instance named `sym`, pre-computed `Float64` value `val`,
and arbitrary-precision definition in terms of `BigFloat`s given by the expression `def`.
Optionally provide a pre-computed `Float64` value `val` which must equal `Float64(def)`.
It will be computed automatically if omitted.

As default, `T` is set to `sym` with the first character converted to uppercase.

Expand All @@ -49,30 +55,36 @@ returns `false`.

# Examples

```jldoctest
julia> IrrationalConstants.@irrational(twoπ, 6.2831853071795864769, 2*big(π))
```jldoctest; setup = :(import IrrationalConstants)
julia> IrrationalConstants.@irrational twoπ 2*big(π)

julia> twoπ
twoπ = 6.2831853071795...

julia> IrrationalConstants.@irrational sqrt2 1.4142135623730950488 √big(2)
julia> IrrationalConstants.@irrational sqrt2 1.4142135623730950488 √big(2)

julia> sqrt2
sqrt2 = 1.4142135623730...

julia> IrrationalConstants.@irrational halfτ 3.14159265358979323846 pi
julia> IrrationalConstants.@irrational halfτ 3.14159265358979323846 pi

julia> halfτ
halfτ = 3.1415926535897...

julia> IrrationalConstants.@irrational sqrt2 1.4142135623730950488 big(2)
ERROR: AssertionError: big($(Expr(:escape, :sqrt2))) isa BigFloat
julia> IrrationalConstants.@irrational sqrt3 1.7320508075688772 big(3)
ERROR: AssertionError: big($(Expr(:escape, :sqrt3))) isa BigFloat

julia> IrrationalConstants.@irrational sqrt2 1.41421356237309 √big(2)
ERROR: AssertionError: Float64($(Expr(:escape, :sqrt2))) == Float64(big($(Expr(:escape, :sqrt2))))
julia> IrrationalConstants.@irrational sqrt5 2.2360679775 √big(5)
ERROR: AssertionError: Float64($(Expr(:escape, :sqrt5))) == Float64(big($(Expr(:escape, :sqrt5))))
```
"""
macro irrational(sym, val, def, T=Symbol(uppercasefirst(string(sym))))
macro irrational(sym::Symbol, val::Float64, def::Union{Symbol,Expr}, T::Symbol=Symbol(uppercasefirst(string(sym))))
irrational(sym, val, def, T)
end
macro irrational(sym::Symbol, def::Union{Symbol,Expr}, T::Symbol=Symbol(uppercasefirst(string(sym))))
irrational(sym, :(big($(esc(sym)))), def, T)
end
function irrational(sym::Symbol, val::Union{Float64,Expr}, def::Union{Symbol,Expr}, T::Symbol)
esym = esc(sym)
qsym = esc(Expr(:quote, sym))
eT = esc(T)
Expand All @@ -90,17 +102,23 @@ macro irrational(sym, val, def, T=Symbol(uppercasefirst(string(sym))))
end
else
# newer Julia versions
isa(def, Symbol) ? quote
function Base.BigFloat(::$eT, r::Base.MPFR.MPFRRoundingMode=Base.MPFR.ROUNDING_MODE[]; precision=precision(BigFloat))
c = BigFloat(; precision=precision)
ccall(($(string("mpfr_const_", def)), :libmpfr),
Cint, (Ref{BigFloat}, Base.MPFR.MPFRRoundingMode), c, r)
return c
if isa(def, Symbol)
# support older Julia versions prior to https://github.com/JuliaLang/julia/pull/51362
r = VERSION < v"1.12.0-DEV.78" ? :(Base.MPFR.ROUNDING_MODE[]) : :(Base.Rounding.rounding_raw(BigFloat))
quote
function Base.BigFloat(::$eT, r::Base.MPFR.MPFRRoundingMode=$r; precision=precision(BigFloat))
devmotion marked this conversation as resolved.
Show resolved Hide resolved
c = BigFloat(; precision=precision)
ccall(($(string("mpfr_const_", def)), :libmpfr),
Cint, (Ref{BigFloat}, Base.MPFR.MPFRRoundingMode), c, r)
return c
end
end
end : quote
function Base.BigFloat(::$eT; precision=precision(BigFloat))
setprecision(BigFloat, precision) do
$(esc(def))
else
quote
function Base.BigFloat(::$eT; precision=precision(BigFloat))
setprecision(BigFloat, precision) do
$(esc(def))
end
end
end
end
Expand All @@ -109,8 +127,10 @@ macro irrational(sym, val, def, T=Symbol(uppercasefirst(string(sym))))
struct $T <: IrrationalConstant end
const $esym = $eT()
$bigconvert
Base.Float64(::$eT) = $val
Base.Float32(::$eT) = $(Float32(val))
let v = $val, v64 = Float64(v), v32 = Float32(v)
Base.Float64(::$eT) = v64
Base.Float32(::$eT) = v32
end
Base.show(io::IO, ::$eT) = print(io, $qsym)
@assert isa(big($esym), BigFloat)
@assert Float64($esym) == Float64(big($esym))
Expand Down
48 changes: 24 additions & 24 deletions src/stats.jl
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
# mathematical constants related to statistics

@irrational twoπ 6.2831853071795864769 2 * big(π)
@irrational fourπ 12.566370614359172954 4 * big(π)
@irrational halfπ 1.5707963267948966192 big(π) / 2
@irrational quartπ 0.7853981633974483096 big(π) / 4
@irrational twoπ 2 * big(π)
@irrational fourπ 4 * big(π)
@irrational halfπ big(π) / 2
@irrational quartπ big(π) / 4

@irrational invπ 0.31830988618379067154 inv(big(π))
@irrational twoinvπ 0.63661977236758134308 2 / big(π)
@irrational fourinvπ 1.27323954473516268615 4 / big(π)
@irrational inv2π 0.159154943091895335769 inv(2 * big(π))
@irrational inv4π 0.079577471545947667884 inv(4 * big(π))
@irrational invπ inv(big(π))
@irrational twoinvπ 2 / big(π)
@irrational fourinvπ 4 / big(π)
@irrational inv2π inv(2 * big(π))
@irrational inv4π inv(4 * big(π))

@irrational sqrt2 1.4142135623730950488 sqrt(big(2))
@irrational sqrt3 1.7320508075688772935 sqrt(big(3))
@irrational sqrtπ 1.7724538509055160273 sqrt(big(π))
@irrational sqrt2π 2.5066282746310005024 sqrt(2 * big(π))
@irrational sqrt4π 3.5449077018110320546 sqrt(4 * big(π))
@irrational sqrthalfπ 1.2533141373155002512 sqrt(big(π) / 2)
@irrational sqrt2 sqrt(big(2))
@irrational sqrt3 sqrt(big(3))
@irrational sqrtπ sqrt(big(π))
@irrational sqrt2π sqrt(2 * big(π))
@irrational sqrt4π sqrt(4 * big(π))
@irrational sqrthalfπ sqrt(big(π) / 2)

@irrational invsqrt2 0.7071067811865475244 inv(sqrt(big(2)))
@irrational invsqrtπ 0.5641895835477563 inv(sqrt(big(π)))
@irrational invsqrt2π 0.3989422804014326779 inv(sqrt(2 * big(π)))
@irrational invsqrt2 inv(sqrt(big(2)))
@irrational invsqrtπ inv(sqrt(big(π)))
@irrational invsqrt2π inv(sqrt(2 * big(π)))

@irrational loghalf -0.6931471805599453094 log(inv(big(2)))
@irrational logtwo 0.6931471805599453094 log2
@irrational logten 2.302585092994046 log(big(10))
@irrational logπ 1.1447298858494001741 log(big(π))
@irrational log2π 1.8378770664093454836 log(2 * big(π))
@irrational log4π 2.5310242469692907930 log(4 * big(π))
@irrational loghalf log(inv(big(2)))
@irrational logtwo log2
@irrational logten log(big(10))
@irrational logπ log(big(π))
@irrational log2π log(2 * big(π))
@irrational log4π log(4 * big(π))
132 changes: 103 additions & 29 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ using IrrationalConstants
using Documenter
using Test

const ALLCONSTANTS = filter!(
x -> x isa IrrationalConstants.IrrationalConstant,
map(Base.Fix1(getproperty, IrrationalConstants), names(IrrationalConstants)),
)

@testset "k*pi" begin
@test isapprox(2*pi, twoπ)
@test isapprox(4*pi, fourπ)
Expand Down Expand Up @@ -48,30 +53,47 @@ end
end

@testset "hash" begin
for i in (twoπ, invπ, sqrt2, logtwo), j in (twoπ, invπ, sqrt2, logtwo)
for i in ALLCONSTANTS, j in ALLCONSTANTS
@test isequal(i==j, hash(i)==hash(j))
end
end

@testset "doctests" begin
DocMeta.setdocmeta!(
IrrationalConstants, :DocTestSetup, :(using IrrationalConstants); recursive=true
)
doctest(IrrationalConstants; manual=false)
end

# copied from https://github.com/JuliaLang/julia/blob/cf5ae0369ceae078cf6a29d7aa34f48a5a53531e/test/numbers.jl
# and adapted to irrationals in this package

@testset "IrrationalConstant zero and one" begin
@test one(twoπ) === true
@test zero(twoπ) === false
@test one(typeof(twoπ)) === true
@test zero(typeof(twoπ)) === false
@testset "IrrationalConstants zero and one" begin
for i in ALLCONSTANTS
@test one(i) === true
@test zero(i) === false
@test one(typeof(i)) === true
@test zero(typeof(i)) === false
end
end

@testset "IrrationalConstants iszero, isfinite, isinteger, and isone" begin
for i in ALLCONSTANTS
@test !iszero(i)
@test !isone(i)
@test !isinteger(i)
@test isfinite(i)
end
end

@testset "IrrationalConstants promote_type" begin
for T in (Float16, Float32, Float64)
for i in ALLCONSTANTS
@test T(2.0) * i ≈ T(2.0) * T(i)
@test T(2.0) * i isa T
end
end
end

@testset "IrrationalConstants compared with IrrationalConstants" begin
for i in (twoπ, invπ, sqrt2, logtwo), j in (twoπ, invπ, sqrt2, logtwo)
for i in ALLCONSTANTS, j in ALLCONSTANTS
@test isequal(i==j, Float64(i)==Float64(j))
@test isequal(i!=j, Float64(i)!=Float64(j))
@test isequal(i<=j, Float64(i)<=Float64(j))
Expand All @@ -81,29 +103,31 @@ end
end
end

@testset "IrrationalConstant Inverses, JuliaLang/Julia Issue #30882" begin
@testset "IrrationalConstants Inverses, JuliaLang/Julia Issue #30882" begin
@test @inferred(inv(twoπ)) ≈ 0.15915494309189535
end

@testset "IrrationalConstants compared with Rationals and Floats" begin
@test Float64(twoπ, RoundDown) < twoπ
@test Float64(twoπ, RoundUp) > twoπ
@test !(Float64(twoπ, RoundDown) > twoπ)
@test !(Float64(twoπ, RoundUp) < twoπ)
@test Float64(twoπ, RoundDown) <= twoπ
@test Float64(twoπ, RoundUp) >= twoπ
@test Float64(twoπ, RoundDown) != twoπ
@test Float64(twoπ, RoundUp) != twoπ

@test Float32(twoπ, RoundDown) < twoπ
@test Float32(twoπ, RoundUp) > twoπ
@test !(Float32(twoπ, RoundDown) > twoπ)
@test !(Float32(twoπ, RoundUp) < twoπ)

@test prevfloat(big(twoπ)) < twoπ
@test nextfloat(big(twoπ)) > twoπ
@test !(prevfloat(big(twoπ)) > twoπ)
@test !(nextfloat(big(twoπ)) < twoπ)
for i in ALLCONSTANTS
@test Float64(i, RoundDown) < i
@test Float64(i, RoundUp) > i
@test !(Float64(i, RoundDown) > i)
@test !(Float64(i, RoundUp) < i)
@test Float64(i, RoundDown) <= i
@test Float64(i, RoundUp) >= i
@test Float64(i, RoundDown) != i
@test Float64(i, RoundUp) != i

@test Float32(i, RoundDown) < i
@test Float32(i, RoundUp) > i
@test !(Float32(i, RoundDown) > i)
@test !(Float32(i, RoundUp) < i)

@test prevfloat(big(i)) < i
@test nextfloat(big(i)) > i
@test !(prevfloat(big(i)) > i)
@test !(nextfloat(big(i)) < i)
end

@test 5293386250278608690//842468587426513207 < twoπ
@test !(5293386250278608690//842468587426513207 > twoπ)
Expand Down Expand Up @@ -181,3 +205,53 @@ end
@test sec(quartπ) === Float64(sec(big(quartπ)))
@test cot(quartπ) === Float64(cot(big(quartπ)))
end

# Ref https://github.com/JuliaLang/julia/pull/46054
IrrationalConstants.@irrational irrational_1548_pi 4863.185427757 1548big(pi)
IrrationalConstants.@irrational irrational_inv_1548_pi 1/big(irrational_1548_pi)
@testset "IrrationalConstants.@irrational" begin
@test irrational_1548_pi ≈ 1548big(pi)
@test Float64(irrational_1548_pi) == 1548π
@test irrational_1548_pi ≈ 1548pi
@test irrational_1548_pi != 1548pi
@test irrational_inv_1548_pi ≈ inv(1548big(pi))
@test Float64(irrational_inv_1548_pi) == 1/(1548π)
@test irrational_inv_1548_pi ≈ inv(1548pi)
@test irrational_inv_1548_pi != inv(1548pi)
end

# Ref https://github.com/JuliaLang/julia/pull/50894
@testset "irrational special values" begin
for v ∈ ALLCONSTANTS
@test v === typemin(v) === typemax(v)
end
end

# Ref https://github.com/JuliaLang/julia/pull/55911
@testset "logtwo to `BigFloat` with `setrounding`" begin
function irrational_to_big_float(c::AbstractIrrational)
BigFloat(c)
end

function irrational_to_big_float_with_rounding_mode(c::AbstractIrrational, rm::RoundingMode)
f = () -> irrational_to_big_float(c)
setrounding(f, BigFloat, rm)
end

function irrational_to_big_float_with_rounding_mode_and_precision(c::AbstractIrrational, rm::RoundingMode, prec::Int)
f = () -> irrational_to_big_float_with_rounding_mode(c, rm)
setprecision(f, BigFloat, prec)
end

# Prior to https://github.com/JuliaLang/julia/pull/40872 `setprecision(BigFloat, precision)` required precision >= 2
minprecision = VERSION < v"1.8.0-DEV.367" ? 2 : 1

# logtwo is the only constant defined based on an MPFR constant (similar to π, γ, catalan)
c = logtwo
for p ∈ minprecision:40
@test (
irrational_to_big_float_with_rounding_mode_and_precision(c, RoundDown, p) < c <
irrational_to_big_float_with_rounding_mode_and_precision(c, RoundUp, p)
)
end
end
Loading