Skip to content

Commit 0e4a682

Browse files
authored
Fix invpow and invlog domains (#23)
1 parent 34c1adf commit 0e4a682

File tree

2 files changed

+45
-8
lines changed

2 files changed

+45
-8
lines changed

src/functions.jl

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,44 @@ function square(x::Real)
1212
end
1313

1414

15-
invpow2(x::Real, p::Integer) = sign(x) * abs(x)^inv(p)
16-
invpow2(x::Real, p::Real) = x zero(x) ? x^inv(p) : throw(DomainError(x, "inverse for x^$p is not defined at $x"))
17-
invpow2(x, p) = x^inv(p)
15+
function invpow2(x::Real, p::Integer)
16+
if x zero(x) || isodd(p)
17+
copysign(abs(x)^inv(p), x)
18+
else
19+
throw(DomainError(x, "inverse for x^$p is not defined at $x"))
20+
end
21+
end
22+
function invpow2(x::Real, p::Real)
23+
if x zero(x)
24+
x^inv(p)
25+
else
26+
throw(DomainError(x, "inverse for x^$p is not defined at $x"))
27+
end
28+
end
29+
function invpow2(x, p::Real)
30+
# complex x^p is only invertible for p = 1/n
31+
if isinteger(inv(p))
32+
x^inv(p)
33+
else
34+
throw(DomainError(x, "inverse for x^$p is not defined at $x"))
35+
end
36+
end
1837

19-
invpow1(b, x) = log(abs(b), abs(x))
38+
function invpow1(b::Real, x::Real)
39+
if b zero(b) && x zero(x)
40+
log(b, x)
41+
else
42+
throw(DomainError(x, "inverse for $b^x is not defined at $x"))
43+
end
44+
end
2045

21-
invlog1(b::Real, x::Real) = b zero(b) && x zero(x) ? b^x : throw(DomainError(x, "inverse for log($b, x) is not defined at $x"))
46+
function invlog1(b::Real, x::Real)
47+
if b zero(b)
48+
b^x
49+
else
50+
throw(DomainError(x, "inverse for log($b, x) is not defined at $x"))
51+
end
52+
end
2253
invlog1(b, x) = b^x
2354

2455
invlog2(b, x) = x^inv(b)

test/test_inverse.jl

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ InverseFunctions.inverse(f::Bar) = Bar(inv(f.A))
3737
x = rand()
3838
for f in (
3939
foo, inv_foo, log, log2, log10, log1p, sqrt,
40-
Base.Fix2(^, rand()), Base.Fix2(^, rand([-10:-1; 1:10])), Base.Fix1(^, rand()), Base.Fix1(log, rand()), Base.Fix2(log, rand()),
40+
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()),
4141
)
4242
InverseFunctions.test_inverse(f, x)
4343
end
@@ -55,10 +55,16 @@ InverseFunctions.inverse(f::Bar) = Bar(inv(f.A))
5555
# ensure that inverses have domains compatible with original functions
5656
@test_throws DomainError inverse(Base.Fix1(*, 0))
5757
@test_throws DomainError inverse(Base.Fix2(^, 0))
58+
@test_throws DomainError inverse(Base.Fix1(log, -2))(5)
5859
@test_throws DomainError inverse(Base.Fix1(log, 2))(-5)
59-
InverseFunctions.test_inverse(Base.Fix1(log, 2), -5 + 0im)
60+
InverseFunctions.test_inverse(inverse(Base.Fix1(log, 2)), complex(-5))
6061
@test_throws DomainError inverse(Base.Fix2(^, 0.5))(-5)
61-
InverseFunctions.test_inverse(Base.Fix2(^, 0.5), -5 + 0im)
62+
@test_throws DomainError inverse(Base.Fix2(^, 0.51))(complex(-5))
63+
InverseFunctions.test_inverse(Base.Fix2(^, 0.5), complex(-5))
64+
@test_throws DomainError inverse(Base.Fix2(^, 2))(-5)
65+
@test_throws DomainError inverse(Base.Fix1(^, 2))(-5)
66+
@test_throws DomainError inverse(Base.Fix1(^, -2))(3)
67+
@test_throws DomainError inverse(Base.Fix1(^, -2))(3)
6268

6369
A = rand(5, 5)
6470
for f in (

0 commit comments

Comments
 (0)