在objective-c中实现-hash时如何处理浮点数和双精度数

时间:2023-01-15 14:49:29

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:

我是Objective-C的新手,我正在寻找处理原始浮点数的最佳方法,并在Objective-C类中实现-hash方法时加倍。在这个问题中,我已经找到了关于isEqual和hash的一些好建议:

Best practices for overriding isEqual: and hash

覆盖isEqual:和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 ?

但我不确定这是正确的方法。有任何想法吗 ?

2 个解决方案

#1


12  

On the assumption that Apple's implementation of -hash is adequate, what is wrong with

假设Apple的-hash实现足够,那有什么问题

result = [[NSNumber numberWithDouble: [self latitude]] hash];

Or using the modern syntax

或者使用现代语法

result = [@([self latitude]) hash];

#2


7  

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:

@JeremyP关于使用NSNumber的建议非常好,但我更深入地了解了这一点。由于CoreFoundation是开源的,我发现CFNumber如何实现散列函数,这就是我发现的:

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:

来自CoreFoundation的原始源代码评论:

/* 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.

来自opensource.apple.com上的文件ForFoundationOnly.h。

#1


12  

On the assumption that Apple's implementation of -hash is adequate, what is wrong with

假设Apple的-hash实现足够,那有什么问题

result = [[NSNumber numberWithDouble: [self latitude]] hash];

Or using the modern syntax

或者使用现代语法

result = [@([self latitude]) hash];

#2


7  

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:

@JeremyP关于使用NSNumber的建议非常好,但我更深入地了解了这一点。由于CoreFoundation是开源的,我发现CFNumber如何实现散列函数,这就是我发现的:

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:

来自CoreFoundation的原始源代码评论:

/* 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.

来自opensource.apple.com上的文件ForFoundationOnly.h。