From 3f5c5c15c80dc4ef0a5e61cff75d22f4217891a8 Mon Sep 17 00:00:00 2001 From: Yuto Horikawa Date: Mon, 5 Feb 2024 12:36:32 +0900 Subject: [PATCH] Add `Base.hash(::Quaternion, ::UInt)` (#136) * add `Base.hash(::Quaternion)` * add tests for `hash` * update hash for more readability * replace `==` with `===` in hash test --- src/Quaternion.jl | 11 +++++++++++ test/Quaternion.jl | 10 ++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/Quaternion.jl b/src/Quaternion.jl index e05dcdd..933cb69 100644 --- a/src/Quaternion.jl +++ b/src/Quaternion.jl @@ -288,6 +288,17 @@ function Base.isequal(q::Quaternion, w::Quaternion) isequal(q.s, w.s) & isequal(q.v1, w.v1) & isequal(q.v2, w.v2) & isequal(q.v3, w.v3) end +if UInt === UInt64 + const h_imags = 0xfa29df508725c1bf, 0x5e6c4b26a400626d, 0x8dfd375bac9f9403 +else + const h_imags = 0x62802719, 0x5a9b072e, 0x209019b1 +end +const hash_0_imags = hash.(0, h_imags) + +function Base.hash(z::Quaternion, h::UInt) + hash(real(z), h ⊻ xor(xor.(hash.(imag_part(z), h_imags), hash_0_imags)...)) +end + """ extend_analytic(f, q::Quaternion) diff --git a/test/Quaternion.jl b/test/Quaternion.jl index 737e397..fa3dc91 100644 --- a/test/Quaternion.jl +++ b/test/Quaternion.jl @@ -66,6 +66,16 @@ end @test !isequal(Quaternion(NaN, 0.0, Inf, -Inf), Quaternion(NaN, -0.0, Inf, -Inf)) end + @testset "hash" begin + # https://github.com/JuliaGeometry/Quaternions.jl/issues/135 + @test hash(0) === hash(quat(0)) === hash(0.0) === hash(quat(0.0)) + @test hash(1) === hash(quat(1)) === hash(1.0) === hash(quat(1.0)) + @test hash(quat(-0.0)) ≠ hash(quat(+0.0)) + @test allunique([hash(quat(1,0,0,0)), hash(quat(0,1,0,0)), hash(quat(0,0,1,0)), hash(quat(0,0,0,1))]) + @test hash(57, UInt(42)) === hash(quat(57), UInt(42)) + @test length(unique(Quaternion[quat(2), quat(big"2")])) == 1 + end + @testset "convert" begin @test convert(Quaternion{Float64}, 1) === Quaternion(1.0) @test convert(Quaternion{Float64}, Quaternion(1, 2, 3, 4)) ===