Decimals.jl icon indicating copy to clipboard operation
Decimals.jl copied to clipboard

Decimal not usable as Dict key: no hash method defined

Open Jasha10 opened this issue 6 years ago • 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

Jasha10 avatar Jul 19 '19 15:07 Jasha10

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.

Jasha10 avatar Jul 27 '19 23:07 Jasha10

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

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

Jasha10 avatar Aug 12 '19 19:08 Jasha10

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

tencnivel avatar Jan 25 '20 11:01 tencnivel

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.

stevengj avatar May 14 '20 21:05 stevengj

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

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

jmkuhn avatar Feb 09 '21 17:02 jmkuhn