• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

JuliaLang / julia / #37755

20 Apr 2024 11:40PM UTC coverage: 87.308% (-0.09%) from 87.396%
#37755

push

local

web-flow
make `one(::AbstractMatrix)` use `similar` instead of `zeros` (#54162)

13 of 13 new or added lines in 1 file covered. (100.0%)

117 existing lines in 16 files now uncovered.

76156 of 87227 relevant lines covered (87.31%)

14990985.99 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

76.99
/base/irrationals.jl
1
# This file is a part of Julia. License is MIT: https://julialang.org/license
2

3
## general machinery for irrational mathematical constants
4

5
"""
6
    AbstractIrrational <: Real
7

8
Number type representing an exact irrational value, which is automatically rounded to the correct precision in
9
arithmetic operations with other numeric quantities.
10

11
Subtypes `MyIrrational <: AbstractIrrational` should implement at least `==(::MyIrrational, ::MyIrrational)`,
12
`hash(x::MyIrrational, h::UInt)`, and `convert(::Type{F}, x::MyIrrational) where {F <: Union{BigFloat,Float32,Float64}}`.
13

14
If a subtype is used to represent values that may occasionally be rational (e.g. a square-root type that represents `√n`
15
for integers `n` will give a rational result when `n` is a perfect square), then it should also implement
16
`isinteger`, `iszero`, `isone`, and `==` with `Real` values (since all of these default to `false` for
17
`AbstractIrrational` types), as well as defining [`hash`](@ref) to equal that of the corresponding `Rational`.
18
"""
19
abstract type AbstractIrrational <: Real end
20

21
"""
22
    Irrational{sym} <: AbstractIrrational
23

24
Number type representing an exact irrational value denoted by the
25
symbol `sym`, such as [`π`](@ref pi), [`ℯ`](@ref) and [`γ`](@ref Base.MathConstants.eulergamma).
26

27
See also [`AbstractIrrational`](@ref).
28
"""
29
struct Irrational{sym} <: AbstractIrrational end
3✔
30

31
typemin(::Type{T}) where {T<:Irrational} = T()
5✔
32
typemax(::Type{T}) where {T<:Irrational} = T()
5✔
33

34
show(io::IO, x::Irrational{sym}) where {sym} = print(io, sym)
8✔
35

36
function show(io::IO, ::MIME"text/plain", x::Irrational{sym}) where {sym}
4✔
37
    if get(io, :compact, false)::Bool
4✔
38
        print(io, sym)
1✔
39
    else
40
        print(io, sym, " = ", string(float(x))[1:min(end,15)], "...")
3✔
41
    end
42
end
43

44
promote_rule(::Type{<:AbstractIrrational}, ::Type{Float16}) = Float16
×
45
promote_rule(::Type{<:AbstractIrrational}, ::Type{Float32}) = Float32
×
46
promote_rule(::Type{<:AbstractIrrational}, ::Type{<:AbstractIrrational}) = Float64
×
47
promote_rule(::Type{<:AbstractIrrational}, ::Type{T}) where {T<:Real} = promote_type(Float64, T)
143,859✔
48
promote_rule(::Type{S}, ::Type{T}) where {S<:AbstractIrrational,T<:Number} = promote_type(promote_type(S, real(T)), T)
2✔
49

50
AbstractFloat(x::AbstractIrrational) = Float64(x)::Float64
102✔
51
Float16(x::AbstractIrrational) = Float16(Float32(x)::Float32)
868✔
52
Complex{T}(x::AbstractIrrational) where {T<:Real} = Complex{T}(T(x))
5✔
53

54
# XXX this may change `DEFAULT_PRECISION`, thus not effect free
55
@assume_effects :total function Rational{T}(x::AbstractIrrational) where T<:Integer
3✔
56
    o = precision(BigFloat)
3✔
57
    p = 256
3✔
58
    while true
3✔
59
        setprecision(BigFloat, p)
3✔
60
        bx = BigFloat(x)
3✔
61
        r = rationalize(T, bx, tol=0)
3✔
62
        if abs(BigFloat(r) - bx) > eps(bx)
3✔
63
            setprecision(BigFloat, o)
3✔
64
            return r
3✔
65
        end
66
        p += 32
×
67
    end
×
68
end
69
Rational{BigInt}(x::AbstractIrrational) = throw(ArgumentError("Cannot convert an AbstractIrrational to a Rational{BigInt}: use rationalize(BigInt, x) instead"))
1✔
70

71
@assume_effects :total function (t::Type{T})(x::AbstractIrrational, r::RoundingMode) where T<:Union{Float32,Float64}
42✔
72
    setprecision(BigFloat, 256) do
42✔
73
        T(BigFloat(x)::BigFloat, r)
42✔
74
    end
75
end
76

77
float(::Type{<:AbstractIrrational}) = Float64
×
78

79
==(::Irrational{s}, ::Irrational{s}) where {s} = true
×
80
==(::AbstractIrrational, ::AbstractIrrational) = false
×
81

82
<(::Irrational{s}, ::Irrational{s}) where {s} = false
×
83
function <(x::AbstractIrrational, y::AbstractIrrational)
12✔
84
    Float64(x) != Float64(y) || throw(MethodError(<, (x, y)))
48✔
85
    return Float64(x) < Float64(y)
48✔
86
end
87

88
<=(::Irrational{s}, ::Irrational{s}) where {s} = true
×
89
<=(x::AbstractIrrational, y::AbstractIrrational) = x==y || x<y
24✔
90

91
# Irrationals, by definition, can't have a finite representation equal them exactly
92
==(x::AbstractIrrational, y::Real) = false
×
93
==(x::Real, y::AbstractIrrational) = false
×
94

95
# Irrational vs AbstractFloat
96
<(x::AbstractIrrational, y::Float64) = Float64(x,RoundUp) <= y
5✔
97
<(x::Float64, y::AbstractIrrational) = x <= Float64(y,RoundDown)
102✔
98
<(x::AbstractIrrational, y::Float32) = Float32(x,RoundUp) <= y
2✔
99
<(x::Float32, y::AbstractIrrational) = x <= Float32(y,RoundDown)
18✔
100
<(x::AbstractIrrational, y::Float16) = Float32(x,RoundUp) <= y
1✔
101
<(x::Float16, y::AbstractIrrational) = x <= Float32(y,RoundDown)
1✔
102
<(x::AbstractIrrational, y::BigFloat) = setprecision(precision(y)+32) do
2✔
103
    big(x) < y
2✔
104
end
105
<(x::BigFloat, y::AbstractIrrational) = setprecision(precision(x)+32) do
2✔
106
    x < big(y)
2✔
107
end
108

109
<=(x::AbstractIrrational, y::AbstractFloat) = x < y
3✔
110
<=(x::AbstractFloat, y::AbstractIrrational) = x < y
3✔
111

112
# Irrational vs Rational
113
@assume_effects :total function rationalize(::Type{T}, x::AbstractIrrational; tol::Real=0) where T
3✔
114
    return rationalize(T, big(x), tol=tol)
3✔
115
end
116
@assume_effects :total function lessrational(rx::Rational{<:Integer}, x::AbstractIrrational)
4✔
117
    # an @assume_effects :total version of `<` for determining if the rationalization of
118
    # an irrational number required rounding up or down
119
    return rx < big(x)
4✔
120
end
121
function <(x::AbstractIrrational, y::Rational{T}) where T
122
    T <: Unsigned && x < 0.0 && return true
2✔
123
    rx = rationalize(T, x)
2✔
124
    if lessrational(rx, x)
2✔
125
        return rx < y
2✔
126
    else
127
        return rx <= y
×
128
    end
129
end
130
function <(x::Rational{T}, y::AbstractIrrational) where T
1✔
131
    T <: Unsigned && y < 0.0 && return false
2✔
132
    ry = rationalize(T, y)
2✔
133
    if lessrational(ry, y)
2✔
134
        return x <= ry
2✔
135
    else
136
        return x < ry
×
137
    end
138
end
139
<(x::AbstractIrrational, y::Rational{BigInt}) = big(x) < y
1✔
140
<(x::Rational{BigInt}, y::AbstractIrrational) = x < big(y)
1✔
141

142
<=(x::AbstractIrrational, y::Rational) = x < y
1✔
143
<=(x::Rational, y::AbstractIrrational) = x < y
1✔
144

145
isfinite(::AbstractIrrational) = true
×
146
isinteger(::AbstractIrrational) = false
×
147
iszero(::AbstractIrrational) = false
×
148
isone(::AbstractIrrational) = false
×
149

150
hash(x::Irrational, h::UInt) = 3*objectid(x) - h
665✔
151

152
widen(::Type{T}) where {T<:Irrational} = T
1✔
153

154
zero(::AbstractIrrational) = false
×
155
zero(::Type{<:AbstractIrrational}) = false
×
156

157
one(::AbstractIrrational) = true
×
158
one(::Type{<:AbstractIrrational}) = true
×
159

160
sign(x::AbstractIrrational) = ifelse(x < zero(x), -1.0, 1.0)
2✔
161

162
-(x::AbstractIrrational) = -Float64(x)
607✔
163
for op in Symbol[:+, :-, :*, :/, :^]
164
    @eval $op(x::AbstractIrrational, y::AbstractIrrational) = $op(Float64(x),Float64(y))
12✔
165
end
166
*(x::Bool, y::AbstractIrrational) = ifelse(x, Float64(y), 0.0)
2,244✔
167

168
round(x::Irrational, r::RoundingMode) = round(float(x), r)
10✔
169

170
"""
171
    @irrational sym [val] def
172

173
Define a new `Irrational` value, `sym`, with arbitrary-precision definition in terms
174
of `BigFloat`s given by the expression `def`.
175

176
Optionally provide a pre-computed `Float64` value `val` which must equal `Float64(def)`.
177
`val` will be computed automatically if omitted.
178

179
An `AssertionError` is thrown when either `big(def) isa BigFloat` or `Float64(val) == Float64(def)`
180
returns `false`.
181

182
!!! warning
183
    This macro should not be used outside of `Base` Julia.
184

185
    The macro creates a new type `Irrational{:sym}` regardless of where it's invoked. This can
186
    lead to conflicting definitions if two packages define an irrational number with the same
187
    name but different values.
188

189

190
# Examples
191
```jldoctest
192
julia> Base.@irrational twoπ 2*big(π)
193

194
julia> twoπ
195
twoπ = 6.2831853071795...
196

197
julia> Base.@irrational sqrt2 1.4142135623730950488 √big(2)
198

199
julia> sqrt2
200
sqrt2 = 1.4142135623730...
201

202
julia> Base.@irrational sqrt2 1.4142135623730950488 big(2)
203
ERROR: AssertionError: big($(Expr(:escape, :sqrt2))) isa BigFloat
204

205
julia> Base.@irrational sqrt2 1.41421356237309 √big(2)
206
ERROR: AssertionError: Float64($(Expr(:escape, :sqrt2))) == Float64(big($(Expr(:escape, :sqrt2))))
207
```
208
"""
209
macro irrational(sym, val, def)
2✔
210
    irrational(sym, val, def)
2✔
211
end
212
macro irrational(sym, def)
1✔
213
    irrational(sym, :(big($(esc(sym)))), def)
1✔
214
end
215
function irrational(sym, val, def)
3✔
216
    esym = esc(sym)
3✔
217
    qsym = esc(Expr(:quote, sym))
3✔
218
    bigconvert = isa(def,Symbol) ? quote
3✔
219
        function Base.BigFloat(::Irrational{$qsym}, r::MPFR.MPFRRoundingMode=MPFR.ROUNDING_MODE[]; precision=precision(BigFloat))
2,785✔
220
            c = BigFloat(;precision=precision)
800✔
221
            ccall(($(string("mpfr_const_", def)), :libmpfr),
800✔
222
                  Cint, (Ref{BigFloat}, MPFR.MPFRRoundingMode), c, r)
223
            return c
800✔
224
        end
225
    end : quote
226
        function Base.BigFloat(::Irrational{$qsym}; precision=precision(BigFloat))
77✔
227
            setprecision(BigFloat, precision) do
71✔
228
                $(esc(def))
71✔
229
            end
230
        end
231
    end
232
    quote
3✔
233
        const $esym = Irrational{$qsym}()
234
        $bigconvert
235
        let v = $val, v64 = Float64(v), v32 = Float32(v)
236
            Base.Float64(::Irrational{$qsym}) = v64
11✔
237
            Base.Float32(::Irrational{$qsym}) = v32
3✔
238
        end
239
        @assert isa(big($esym), BigFloat)
240
        @assert Float64($esym) == Float64(big($esym))
241
        @assert Float32($esym) == Float32(big($esym))
242
    end
243
end
244

245
big(x::AbstractIrrational) = BigFloat(x)
190✔
246
big(::Type{<:AbstractIrrational}) = BigFloat
×
247

248
# align along = for nice Array printing
249
function alignment(io::IO, x::AbstractIrrational)
×
250
    m = match(r"^(.*?)(=.*)$", sprint(show, x, context=io, sizehint=0))
×
251
    m === nothing ? (length(sprint(show, x, context=io, sizehint=0)), 0) :
×
252
    (length(something(m.captures[1])), length(something(m.captures[2])))
253
end
254

255
# inv
256
inv(x::AbstractIrrational) = 1/x
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc