Skip to content
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
20 changes: 12 additions & 8 deletions src/Infinities.jl
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
module Infinities

import Base: angle, isone, iszero, isinf, isfinite, abs, one, oneunit, zero, isless, inv,
+, -, *, ==, <, ≤, >, ≥, fld, cld, div, mod, min, max, sign, signbit,
+, -, *, ^, ==, <, ≤, >, ≥, fld, cld, div, mod, min, max, sign, signbit,
string, show, promote_rule, convert, getindex,
Bool, Integer

export ∞, ℵ₀, ℵ₁, RealInfinity, ComplexInfinity, InfiniteCardinal, NotANumber
export ∞, ℵ₀, ℵ₁, RealInfinity, ComplexInfinity, InfiniteCardinal, NotANumber, PositiveInfinity, NegativeInfinity
# The following is commented out for now to avoid conflicts with Infinity.jl
# export Infinity

Expand Down Expand Up @@ -45,13 +45,18 @@ oneunit(::Infinity) = 1
zero(::Infinity) = 0
zero(::Type{Infinity}) = 0

struct RealInfinity <: Real
signbit::Bool
end
abstract type RealInfinity <: Real end
struct PositiveInfinity <: RealInfinity end
struct NegativeInfinity <: RealInfinity end

signbit(::PositiveInfinity) = false
signbit(::NegativeInfinity) = true
one(::RealInfinity) = 1.0

RealInfinity() = RealInfinity(false)
RealInfinity(::Infinity) = RealInfinity()
RealInfinity() = PositiveInfinity()
RealInfinity(::Infinity) = PositiveInfinity()
RealInfinity(x::RealInfinity) = x
RealInfinity(x::Bool) = ifelse(x, NegativeInfinity(), PositiveInfinity())

_convert(::Type{Float16}, x::RealInfinity) = sign(x)*Inf16
_convert(::Type{Float32}, x::RealInfinity) = sign(x)*Inf32
Expand All @@ -63,7 +68,6 @@ for Typ in (RealInfinity, Infinity)
@eval Bool(x::$Typ) = throw(InexactError(:Bool, Bool, x)) # ambiguity fix
end

signbit(y::RealInfinity) = y.signbit
sign(y::RealInfinity) = 1-2signbit(y)
angle(x::RealInfinity) = π*signbit(x)

Expand Down
20 changes: 17 additions & 3 deletions src/algebra.jl
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
@inline infpromote(x, y) = Base._promote(x, y)
@inline infpromote(x::ExtendedComplex, y::AllInfinities) = (x, ComplexInfinity(y))
@inline infpromote(x::ExtendedComplex, y::ComplexInfinity) = Base._promote(x, y)
@inline infpromote(x::Real, y::InfiniteCardinal) = (x, ∞)
@inline infpromote(x::Real, ::InfiniteCardinal) = (x, ∞)
@inline infpromote(x::Integer, y::InfiniteCardinal) = (x, y)
@inline infpromote(x::RealInfinity, y::Union{Integer, Rational}) = (x, float(y))
@inline infpromote(x::Union{Integer, Rational}, y::RealInfinity) = (float(x), y)
@inline infpromote(x::RealInfinity, ::InfiniteCardinal) = (x, ∞)


# sign
+(::Infinity) = RealInfinity()
-(::Infinity) = RealInfinity(true)
-(y::RealInfinity) = RealInfinity(!y.signbit)
-(y::RealInfinity) = RealInfinity(!signbit(y))
-(y::ComplexInfinity{B}) where B<:Integer = sign(y) == 1 ? ComplexInfinity(one(B)) : ComplexInfinity(zero(B))
+(x::InfiniteCardinal) = x
-(::InfiniteCardinal) = -∞
Expand Down Expand Up @@ -88,7 +91,18 @@ for OP in (:fld,:cld,:div)
end
end

# Base.literal_pow
# power
# Although the base implementation can cover these cases, it can change overtime and yield inconsistent results.
# ref: https://github.com/JuliaMath/Infinities.jl/actions/runs/19993302836/
_infpow(::PositiveInfinity, p) = ifelse(iszero(p), one(p), ifelse(p > 0, +∞, +zero(p)))
function _infpow(x::NegativeInfinity, p)
!isinteger(p) && throw(Base.Math.throw_exp_domainerror(x))
iszero(p) && return one(p)
isodd(p) && return ifelse(p > 0, -∞, -zero(p))
return ifelse(p > 0, +∞, +zero(p))
end
^(x::RealInfinity, p::Real) = _infpow(infpromote(x, p)...)
^(x::RealInfinity, p::Integer) = _infpow(infpromote(x, p)...)

# inv
inv(::Union{Infinity,InfiniteCardinal}) = 0
Expand Down
2 changes: 2 additions & 0 deletions src/ambiguities.jl
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ for Typ in (Complex, Rational, Complex{Bool}, Integer)
@eval *(x::$Typ, y::AllInfinities) = _mul(x, y)
end

^(x::RealInfinity, y::Rational) = _infpow(infpromote(x, y)...)

for Typ in (Rational, )
@eval mod(::IntegerInfinities, ::$Typ) = NotANumber()
@eval mod(x::$Typ, y::IntegerInfinities) = _mod(x, y)
Expand Down
6 changes: 3 additions & 3 deletions src/interface.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ iszero(::AllInfinities) = false
isinf(::AllInfinities) = true
isfinite(::AllInfinities) = false

promote_rule(::Type{Infinity}, ::Type{RealInfinity}) = RealInfinity # not detected by CodeCov. Removing this results in failed tests.
promote_rule(::Type{Infinity}, ::Type{<:RealInfinity}) = RealInfinity # not detected by CodeCov. Removing this results in failed tests.
promote_rule(::Type{Infinity}, ::Type{ComplexInfinity{T}}) where T = ComplexInfinity{T}
promote_rule(::Type{RealInfinity}, ::Type{ComplexInfinity{T}}) where T = ComplexInfinity{T}
promote_rule(::Type{ComplexInfinity{T}}, ::Type{RealInfinity}) where T<:Integer = ComplexInfinity{T}
promote_rule(::Type{<:RealInfinity}, ::Type{ComplexInfinity{T}}) where T = ComplexInfinity{T}
promote_rule(::Type{ComplexInfinity{T}}, ::Type{<:RealInfinity}) where T<:Integer = ComplexInfinity{T}
promote_rule(::Type{ComplexInfinity{T}}, ::Type{ComplexInfinity{S}}) where {T, S} = ComplexInfinity{promote_type(T, S)}
35 changes: 35 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,29 @@ using Aqua
@test (-∞)*2 ≡ 2*(-∞) ≡ -2 * ∞ ≡ ∞ * (-2) ≡ (-2) * RealInfinity() ≡ -∞
@test (-∞)*2.3 ≡ 2.3*(-∞) ≡ -2.3 * ∞ ≡ ∞ * (-2.3) ≡ (-2.3) * RealInfinity() ≡ -∞

@testset "power" begin
# zero
@test (+∞)^0.0 ≡ (-∞)^0.0 ≡ 1.0

# positive even/odd/fraction
@test (+∞)^2.0 ≡ (-∞)^2.0 ≡ +∞
@test (+∞)^1.0 ≡ +∞
@test (-∞)^1.0 ≡ -∞
@test (+∞)^0.5 ≡ +∞
@test_throws DomainError (-∞)^0.5

# negative even/odd/fraction
@test (+∞)^(-2.0) ≡ (-∞)^(-2.0) ≡ 0.0
@test (+∞)^(-1.0) ≡ 0.0
@test (-∞)^(-1.0) ≡ -0.0
@test (+∞)^(-0.5) ≡ 0.0
@test_throws DomainError (-∞)^(-0.5)

# irrational
@test (+∞)^π ≡ +∞
@test_throws DomainError (-∞)^π
end

@test isinf(-∞)
@test !isfinite(-∞)

Expand Down Expand Up @@ -301,14 +324,26 @@ using Aqua
@test Base.literal_pow(^, ℵ₀, Val(0)) ≡ ℵ₀^0 ≡ 1
@test Base.literal_pow(^, ℵ₀, Val(1)) ≡ ℵ₀^1 ≡ ℵ₀
@test Base.literal_pow(^, ℵ₀, Val(-1)) ≡ ℵ₀^(-1) ≡ 0
@test Base.literal_pow(^, ℵ₀, Val(2)) ≡ ℵ₀^2 ≡ ℵ₀
@test Base.literal_pow(^, ℵ₀, Val(-2)) ≡ ℵ₀^(-2) ≡ 0

@test Base.literal_pow(^, ∞, Val(0)) ≡ ∞^0 ≡ 1
@test Base.literal_pow(^, ∞, Val(1)) ≡ ∞^1 ≡ ∞
@test Base.literal_pow(^, ∞, Val(-1)) ≡ ∞^(-1) ≡ 0
@test Base.literal_pow(^, ∞, Val(2)) ≡ ∞^2 ≡ ∞
@test Base.literal_pow(^, ∞, Val(-2)) ≡ ∞^(-2) ≡ 0

@test Base.literal_pow(^, +∞, Val(0)) ≡ (+∞)^0 ≡ 1.0
@test Base.literal_pow(^, +∞, Val(1)) ≡ (+∞)^1 ≡ +∞
@test Base.literal_pow(^, +∞, Val(-1)) ≡ (+∞)^(-1) ≡ 0.0
@test Base.literal_pow(^, +∞, Val(2)) ≡ (+∞)^2 ≡ +∞
@test Base.literal_pow(^, +∞, Val(-2)) ≡ (+∞)^(-2) ≡ 0.0

@test Base.literal_pow(^, -∞, Val(0)) ≡ (-∞)^0 ≡ 1.0
@test Base.literal_pow(^, -∞, Val(1)) ≡ (-∞)^1 ≡ -∞
@test Base.literal_pow(^, -∞, Val(-1)) ≡ (-∞)^(-1) ≡ (VERSION < v"1.12-" ? 0.0 : -0.0)
@test Base.literal_pow(^, -∞, Val(2)) ≡ (-∞)^2 ≡ +∞
@test Base.literal_pow(^, -∞, Val(-2)) ≡ (-∞)^(-2) ≡ 0.0

@test Base.literal_pow(^, ComplexInfinity(0.1), Val(0)) ≡ ComplexInfinity(0.1)^0 ≡ 1.0+0.0im
@test Base.literal_pow(^, ComplexInfinity(0.1), Val(1)) ≡ (ComplexInfinity(0.1))^1 ≡ ComplexInfinity(0.1)
Expand Down
23 changes: 23 additions & 0 deletions test/test_ambiguity.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,27 @@
@test fld(inf, 1//2) ≡ cld(inf, 1//2) ≡ div(inf, 1//2) ≡ inf
@test fld(inf, ∞) ≡ fld(inf, +∞) ≡ fld(inf, ℵ₀) ≡ fld(inf, ComplexInfinity()) ≡ NotANumber()
end

@testset "rational power" begin
# zero
@test (+∞)^(0//1) ≡ (-∞)^(0//1) ≡ 1.0

# positive even/odd/fraction
@test (+∞)^(2//1) ≡ (-∞)^(2//1) ≡ +∞
@test (+∞)^(1//1) ≡ +∞
@test (-∞)^(1//1) ≡ -∞
@test (+∞)^(1//2) ≡ +∞
@test_throws DomainError (-∞)^(1//2)

# negative even/odd/fraction
@test (+∞)^(-2.0) ≡ (-∞)^(-2.0) ≡ 0.0
@test (+∞)^(-1//1) ≡ 0.0
@test (-∞)^(-1//1) ≡ -0.0
@test (+∞)^(-1//2) ≡ 0.0
@test_throws DomainError (-∞)^(-1//2)

# irrational
@test (+∞)^π ≡ +∞
@test_throws DomainError (-∞)^π
end
end
Loading