I'm a newbie at Objective-C and I'm looking for the best way to handle primitive floats and double when implementing the -hash method in an Objective-C class. I've found some good advise on isEqual and hash in general in this question:
Best practices for overriding isEqual: and hash
but it doesn't say anything on how to deal with floats and doubles.
My best attempt:
...
long lat = [[NSNumber numberWithDouble:self.latitude] longValue];
result = prime * result + (int) (lat ^ (lat >>> 32));
...
but I'm not sure this is the correct way. Any ideas ?
Advice of @JeremyP about using NSNumber
was pretty good, but I followed this more into depth. Since CoreFoundation is open source, I found how does CFNumber
implement hashing function and this is what I found:
Split the number to integral and fraction part, hash both parts and sum them. Integral part is hashed by modulo and a hash-factor, fraction part is hashed only by multiplication.
NSUInteger HashDouble(double value) {
double absolute = ABS(value);
double integral = round(absolute);
double fragment = absolute - integral;
NSUInteger integralHash = 2654435761U * fmod(integral, NSUIntegerMax);
NSUInteger fragmentHash = fragment * NSUIntegerMax;
return integralHash + fragmentHash;
}
Original source code from CoreFoundation wth comments:
/* For use by NSNumber and CFNumber.
Hashing algorithm for CFNumber:
M = Max CFHashCode (assumed to be unsigned)
For positive integral values: (N * HASHFACTOR) mod M
For negative integral values: ((-N) * HASHFACTOR) mod M
For floating point numbers that are not integral: hash(integral part) + hash(float part * M)
HASHFACTOR is 2654435761, from Knuth's multiplicative method
*/
#define HASHFACTOR 2654435761U
CF_INLINE CFHashCode _CFHashInt(long i) {
return ((i > 0) ? (CFHashCode)(i) : (CFHashCode)(-i)) * HASHFACTOR;
}
CF_INLINE CFHashCode _CFHashDouble(double d) {
double dInt;
if (d < 0) d = -d;
dInt = floor(d+0.5);
CFHashCode integralHash = HASHFACTOR * (CFHashCode)fmod(dInt, (double)ULONG_MAX);
return (CFHashCode)(integralHash + (CFHashCode)((d - dInt) * ULONG_MAX));
}
From file ForFoundationOnly.h on opensource.apple.com.
On the assumption that Apple's implementation of -hash
is adequate, what is wrong with
result = [[NSNumber numberWithDouble: [self latitude]] hash];
Or using the modern syntax
result = [@([self latitude]) hash];
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With