JuliaMath/Decimals.jl

Decimal not usable as Dict key: no hash method defined

Jasha10 opened this issue · 5 comments

Perhaps the hash could be defined in terms of the has of the underlying fields s, c and q of the Decimal struct. For reference, here is a stacktrace:

julia> d = Dict()
Dict{Any,Any} with 0 entries

julia> d[Decimal(123)] = 456
ERROR: MethodError: no method matching decompose(::Decimal)
Closest candidates are:
  decompose(::BigFloat) at hashing2.jl:133
  decompose(::Float64) at hashing2.jl:122
  decompose(::Float32) at hashing2.jl:111
  ...
Stacktrace:
 [1] hash(::Decimal, ::UInt64) at ./hashing2.jl:32
 [2] hash(::Decimal) at ./hashing.jl:18
 [3] hashindex(::Decimal, ::Int64) at ./dict.jl:169
 [4] ht_keyindex2!(::Dict{Any,Any}, ::Decimal) at ./dict.jl:309
 [5] setindex!(::Dict{Any,Any}, ::Int64, ::Decimal) at ./dict.jl:382
 [6] top-level scope at none:0

Perhaps we could use something like this for the hash function.

using Decimals

function Base.hash(d::Decimal, h::UInt)
    hash(d.s, hash(d.c, hash(d.q, hash(Decimal, h))))
end

d1 = Decimal(1.23)
d2 = Decimal(1.23)
d3 = Decimal(4.56)

@assert d1 == d2
@assert d1 != d3
@assert !(d1 === d2)
@assert !(d1 === d3)
@assert hash(d1) == hash(d2)
@assert hash(d1) != hash(d3)

If everyone agrees, I can create a pull request.

As far as I can tell, implementing hash for Decimals.jl presents similar problems as it does here: JuliaMath/DecFP.jl#97

I think that implementing decompose for the Decimal type would require using BigInt, since Decimal uses BigInt internally.

This issue also makes it impossible to use the 'unique' function

DecFP (master) now supports hashing, though our solution involved BigInt. It's possible that we may find a faster algorithm in the future, but for now at least it works.

Hashing could be supported by adding decompose() similar to the DecFP implementation.

sigexp() is a DecFP function that is documented here.