Skip to content

Commit 3ab59a0

Browse files
authored
Fix log for negative quaternions (#115)
* Add log tests * Add more general failing test * Fix implementation of log for negative quat
1 parent bdf34b9 commit 3ab59a0

File tree

2 files changed

+17
-5
lines changed

2 files changed

+17
-5
lines changed

src/Quaternion.jl

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -259,12 +259,19 @@ for f in (@static(VERSION ≥ v"1.6" ? (:sincos, :sincospi) : (:sincos,)))
259259
end
260260
end
261261

262+
# this implementation is roughly 2x as fast as extend_analytic(log, q)
262263
function Base.log(q::Quaternion)
263-
a = abs(q)
264-
M = abs_imag(q)
265-
theta = atan(M, q.s)
266-
scale = theta / ifelse(iszero(M), oneunit(M), M)
267-
return Quaternion(log(a), q.v1 * scale, q.v2 * scale, q.v3 * scale)
264+
a = abs_imag(q)
265+
theta = atan(a, q.s)
266+
scale = theta / a
267+
if a > 0
268+
return Quaternion(log(abs(q)), scale * q.v1, scale * q.v2, scale * q.v3)
269+
else
270+
# q == real(q), so f(real(q)) may be real or complex.
271+
# we choose to embed complex numbers in the quaternions by identifying the first
272+
# imaginary quaternion basis with the complex imaginary basis.
273+
return Quaternion(log(abs(q.s)), oftype(scale, theta), zero(scale), zero(scale))
274+
end
268275
end
269276

270277
Base.:^(q::Quaternion, w::Quaternion) = exp(w * log(q))

test/Quaternion.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,11 @@ end
385385
@testset "additional properties" begin
386386
@testset "log" begin
387387
@test log(zero(QuaternionF64)) === Quaternion(-Inf, 0, 0, 0)
388+
@test log(one(QuaternionF64)) === Quaternion(0.0, 0, 0, 0)
389+
@test log(-one(QuaternionF64)) == Quaternion(0.0, π, 0, 0)
390+
x = rand()
391+
@test log(quat(x)) == quat(log(x))
392+
@test log(quat(-x)) == Quaternion(reim(log(complex(-x)))..., 0, 0)
388393
end
389394

390395
@testset "exp" begin

0 commit comments

Comments
 (0)