Skip to content

Commit beb5746

Browse files
aplavindevmotion
andauthored
fix inverse(^) domain (#34)
fix inverse(^) domain and more inverse domain fixes Co-authored-by: David Widmann <[email protected]>
1 parent ad56514 commit beb5746

File tree

4 files changed

+36
-13
lines changed

4 files changed

+36
-13
lines changed

Diff for: Project.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "InverseFunctions"
22
uuid = "3587e190-3f89-42d0-90ee-14403ec27112"
3-
version = "0.1.16"
3+
version = "0.1.17"
44

55
[deps]
66
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"

Diff for: src/functions.jl

+13-7
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,20 @@ function square(x)
1313
end
1414

1515

16+
1617
function invpow_arg2(x::Number, p::Real)
1718
if is_real_type(typeof(x))
1819
x zero(x) ? x^inv(p) : # x > 0 - trivially invertible
1920
isinteger(p) && isodd(Integer(p)) ? copysign(abs(x)^inv(p), x) : # p odd - invertible even for x < 0
2021
throw(DomainError(x, "inverse for x^$p is not defined at $x"))
2122
else
22-
# complex x^p is invertible only for p = 1/n
23+
# complex x^p is only invertible for p = 1/n
2324
isinteger(inv(p)) ? x^inv(p) : throw(DomainError(x, "inverse for x^$p is not defined at $x"))
2425
end
2526
end
2627

2728
function invpow_arg1(b::Real, x::Real)
29+
# b < 0 should never happen in actual use: this check is done in inverse(f)
2830
if b zero(b) && x zero(x)
2931
log(b, x)
3032
else
@@ -33,15 +35,19 @@ function invpow_arg1(b::Real, x::Real)
3335
end
3436

3537
function invlog_arg1(b::Real, x::Real)
36-
if b zero(b)
37-
b^x
38-
else
39-
throw(DomainError(x, "inverse for log($b, x) is not defined at $x"))
40-
end
38+
# exception may happen here: check cannot be done in inverse(f) because of log(Real, Complex)
39+
b > zero(b) && !isone(b) || throw(DomainError(x, "inverse for log($b, x) is not defined at $x"))
40+
b^x
4141
end
4242
invlog_arg1(b::Number, x::Number) = b^x
4343

44-
invlog_arg2(b::Number, x::Number) = x^inv(b)
44+
45+
function invlog_arg2(b::Real, x::Real)
46+
# exception may happen here: check cannot be done in inverse(f) because of log(Complex, Real)
47+
x > zero(x) && !isone(x) || throw(DomainError(x, "inverse for log($b, x) is not defined at $x"))
48+
x^inv(b)
49+
end
50+
invlog_arg2(b, x) = x^inv(b)
4551

4652

4753
function invdivrem((q, r)::NTuple{2,Number}, divisor::Number)

Diff for: src/inverse.jl

+9-2
Original file line numberDiff line numberDiff line change
@@ -159,17 +159,24 @@ inverse(::typeof(sqrt)) = square
159159
inverse(::typeof(square)) = sqrt
160160

161161
inverse(::typeof(cbrt)) = Base.Fix2(^, 3)
162+
162163
inverse(f::Base.Fix2{typeof(^)}) = iszero(f.x) ? throw(DomainError(f.x, "Cannot invert x^$(f.x)")) : Base.Fix2(invpow_arg2, f.x)
164+
inverse(f::Base.Fix2{typeof(^), <:Integer}) = isodd(f.x) ? Base.Fix2(invpow_arg2, f.x) : throw(DomainError(f.x, "Cannot invert x^$(f.x)"))
163165
inverse(f::Base.Fix2{typeof(invpow_arg2)}) = Base.Fix2(^, f.x)
166+
167+
inverse(f::Base.Fix1{typeof(^), <:Real}) = f.x > zero(f.x) ? Base.Fix1(invpow_arg1, f.x) : throw(DomainError(f.x, "Cannot invert $(f.x)^x"))
164168
inverse(f::Base.Fix1{typeof(^)}) = Base.Fix1(invpow_arg1, f.x)
165169
inverse(f::Base.Fix1{typeof(invpow_arg1)}) = Base.Fix1(^, f.x)
166-
inverse(f::Base.Fix1{typeof(log)}) = Base.Fix1(invlog_arg1, f.x)
170+
inverse(f::Base.Fix1{typeof(log)}) = isone(f.x) ? throw(DomainError(f.x, "Cannot invert log($(f.x), x)")) : Base.Fix1(invlog_arg1, f.x)
167171
inverse(f::Base.Fix1{typeof(invlog_arg1)}) = Base.Fix1(log, f.x)
168-
inverse(f::Base.Fix2{typeof(log)}) = Base.Fix2(invlog_arg2, f.x)
172+
173+
inverse(f::Base.Fix2{typeof(log)}) = isone(f.x) ? throw(DomainError(f.x, "Cannot invert log(x, $(f.x))")) : Base.Fix2(invlog_arg2, f.x)
169174
inverse(f::Base.Fix2{typeof(invlog_arg2)}) = Base.Fix2(log, f.x)
170175

176+
171177
inverse(f::Base.Fix2{typeof(divrem)}) = Base.Fix2(invdivrem, f.x)
172178
inverse(f::Base.Fix2{typeof(invdivrem)}) = Base.Fix2(divrem, f.x)
179+
173180
inverse(f::Base.Fix2{typeof(fldmod)}) = Base.Fix2(invfldmod, f.x)
174181
inverse(f::Base.Fix2{typeof(invfldmod)}) = Base.Fix2(fldmod, f.x)
175182

Diff for: test/test_inverse.jl

+13-3
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ end
4949
x = rand()
5050
for f in (
5151
foo, inv_foo, log, log2, log10, log1p, sqrt,
52-
Base.Fix2(^, rand()), Base.Fix2(^, rand([-10:-1; 1:10])), Base.Fix1(^, rand()), Base.Fix1(log, rand()), Base.Fix1(log, 1/rand()), Base.Fix2(log, rand()),
52+
Base.Fix2(^, 3*rand() - 0.5), Base.Fix2(^, rand(float.([-10:-1; 1:10]))), Base.Fix1(^, rand()), Base.Fix1(log, rand()), Base.Fix1(log, 1/rand()), Base.Fix2(log, rand()),
5353
)
5454
InverseFunctions.test_inverse(f, x)
5555
end
@@ -92,6 +92,17 @@ end
9292
@test_throws DomainError inverse(Base.Fix2(^, 0.51))(complex(-5))
9393
@test_throws DomainError inverse(Base.Fix2(^, 2))(complex(-5))
9494
InverseFunctions.test_inverse(Base.Fix2(^, 0.5), complex(-5))
95+
@test_throws DomainError inverse(Base.Fix2(^, 2))
96+
@test_throws DomainError inverse(Base.Fix2(^, -4))
97+
InverseFunctions.test_inverse(Base.Fix2(^, 2.0), 4)
98+
@test_throws DomainError inverse(Base.Fix1(^, 2.0))(-4)
99+
@test_throws DomainError inverse(Base.Fix1(^, -2.0))(4)
100+
@test_throws DomainError inverse(Base.Fix1(^, 0))(4)
101+
@test_throws DomainError inverse(Base.Fix1(log, -2))(4)
102+
@test_throws DomainError inverse(Base.Fix1(log, 1))(4)
103+
@test_throws DomainError inverse(Base.Fix2(^, 0))(4)
104+
@test_throws DomainError inverse(Base.Fix2(log, -2))(4)
105+
@test_throws DomainError inverse(Base.Fix2(log, 1))(4)
95106
InverseFunctions.test_inverse(Base.Fix2(^, -1), complex(-5.))
96107
@test_throws DomainError inverse(Base.Fix2(^, 2))(-5)
97108
@test_throws DomainError inverse(Base.Fix1(^, 2))(-5)
@@ -143,11 +154,10 @@ end
143154
InverseFunctions.test_inverse(sqrt, x)
144155
@test_throws DomainError inverse(sqrt)(-x)
145156

146-
InverseFunctions.test_inverse(Base.Fix2(^, 2), x)
147-
@test_throws DomainError inverse(Base.Fix2(^, 2))(-x)
148157
InverseFunctions.test_inverse(Base.Fix2(^, 3), x)
149158
InverseFunctions.test_inverse(Base.Fix2(^, 3), -x)
150159
InverseFunctions.test_inverse(Base.Fix2(^, -3.5), x)
160+
@test_throws DomainError inverse(Base.Fix2(^, 2))(-x)
151161
end
152162

153163
@testset "dates" begin

0 commit comments

Comments
 (0)