18

I was wondering how to hash a double in Java? I have hashed other primitive data and objects. I thought I could use the hashcode method? From what I have seen this looks quite complex. I came across something about creating a seed.

I was wondering any ideas on how to go about this. Hoping to put in with the rest of my hashcode for the class that has the double?

I was wondering if there are issues with me trying to hash arraylists, arrays and other objects in java. Some of my classes contain arraylists.

Many Thanks

Jonathon Reinhart
  • 132,704
  • 33
  • 254
  • 328
daveb
  • 3,465
  • 6
  • 23
  • 28

4 Answers4

31

Double.hashCode() complex? It basically converts double into a long (no magic here, after all they both are simply 64-bit values in memory) and computing long hash is quite simple. The double -> long conversion is done via public static doubleToLongBits(). What is complex about this?

Examples:

Double.valueOf(42.5).hashCode();        //better answer to everything

Long.valueOf(Double.doubleToLongBits(42.5)).hashCode();
Tomasz Nurkiewicz
  • 334,321
  • 69
  • 703
  • 674
  • Hi Tomasz, i tried the hashcode on the double and got the following message cannot be dereferenced. I am running hashcode() method on a getClassMethod() i.e this.getClassMethod().hashCode(); The getClassMethod returns the double. – daveb Mar 10 '12 at 22:44
  • @daveb: have a look at examples I just added to my answer. – Tomasz Nurkiewicz Mar 10 '12 at 22:49
  • Thanks @Thomasz, I did int hash6 = Double.valueOf(this.getClassMethod()).hashCode(); and it compiled without the previous problem. Is the line of code okay to you? Cheers DaveB – daveb Mar 10 '12 at 22:50
  • 1
    The short answer is "don't hash doubles (or floats)". Hashing floating point numbers will not give you reasonable results because of the limits of precision. For instance [`a = 1d/3d;`] followed by [`b = (a * 2 + 1) / 2 - 0.5d;`] will give you different answers as doubles, even though in a perfect world they would be the same. – Phil Jul 10 '18 at 13:37
  • @Phil I second that. Folks hitting this page will see the answer above and take it as a solution where in fact it would break in practice. – ToniAz Mar 22 '19 at 08:55
2

Depending on what you need this for, you could go with a very simple approach of just mod(ing) it.

 int hash(double d) {
   return d % 71; //use a prime number here
 }

If it is just for storing a few doubles in a hash, this should do it. If you want to spread the hash, just increase the "71"

krico
  • 5,723
  • 2
  • 25
  • 28
  • This is a poor hash, it will return the same value for doubles close to each other. And what if your program only needs doubles between 0 and 1? Constant hash. – Tomasz Nurkiewicz Mar 10 '12 at 22:53
  • I am hashing up all the fields of the diff classes, and overriding hashcode, equals and to string for all my classes. So that I can compare objects from them and also make sure that objects are unique as well. I have been using 31 prime number and concatenating the hashcodes into 1. My double is for a price of an item. DaveB – daveb Mar 10 '12 at 22:57
  • 1
    @TomaszNurkiewicz totally agree! That's why I started with "depending on what you need this for". If you "knew" your values were all between 0 and 1 you should use something else. – krico Mar 11 '12 at 13:45
  • -1 this is an extremely poor hash function. It removes the fractional part completely. And in addition, it maps all numbers onto only 71 different ones. – fishinear Jul 25 '13 at 09:57
  • 1
    @fishinear, if you read my comment above yours, I agree with you. – krico Sep 24 '13 at 07:59
2

The way Java does it is to convert the raw bit of a double into a long.

// from Double.
public static long doubleToLongBits(double value) {
    long result = doubleToRawLongBits(value);
    // Check for NaN based on values of bit fields, maximum
    // exponent and nonzero significand.
    if ( ((result & DoubleConsts.EXP_BIT_MASK) ==
          DoubleConsts.EXP_BIT_MASK) &&
         (result & DoubleConsts.SIGNIF_BIT_MASK) != 0L)
        result = 0x7ff8000000000000L;
    return result;
}

public int hashCode() {
    long bits = doubleToLongBits(value);
    return (int)(bits ^ (bits >>> 32));
}

Note: There many values of NaN (and two types) but Java treats them as all the same.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
1

This one worked for me

int h2 = new Double(area).hashCode();
user1599755
  • 149
  • 1
  • 6