我有一个存储纬度/经度/高度的对象,需要可靠而快速的-hashisEqual实现。我使用double来存储所有原语。
公认的Best practices for overriding isEqual: and hash答案看起来不错,但它只谈到integer值。
我的问题是如何处理双倍,因为它们不是精确的值。我想比较小数点后8位内的原语,这已经比GPS芯片本身要精确得多。
这是我到目前为止的想法,是我做得对还是需要改进?
我的-isEqual:实现相当简单:

- (BOOL)isEqualToAGPoint:(AGPoint *)otherPoint
{
  if (fabs(otherPoint->latitude - latitude) > 0.00000001)
    return NO;

  if (fabs(otherPoint->longitude - longitude) > 0.00000001)
    return NO;

  if (fabs(otherPoint->altitude - altitude) > 0.00000001)
    return NO;

  return YES;
}

但我不太确定我的-hash实现:
- (NSUInteger)hash
{
  NSUInteger prime = 31;
  NSUInteger result = 1;

  result = prime * result + lround(latitude * 100000000);
  result = prime * result + lround(longitude * 100000000);
  result = prime * result + lround(altitude * 100000000);

  return result;
}

一个快速测试表明,它似乎可以满足我的需要:
// all three have the same longitude and altitude, while a and b have slightly different (but should be considered identical) latitudes, while c's latitude is just different enough to be considered not equal to the a and b
AGPoint *a = [[AGPoint alloc] initWithLatitude:-16.922608127 longitude:145.77124538 altitude:2.74930134];
AGPoint *b = [[AGPoint alloc] initWithLatitude:-16.922608128 longitude:145.77124538 altitude:2.74930134];
AGPoint *c = [[AGPoint alloc] initWithLatitude:-16.922608147 longitude:145.77124538 altitude:2.74930134];

NSLog(@"a == b: %i", (int)[a isEqual:b]);
NSLog(@"a == c: %i", (int)[a isEqual:c]);
NSLog(@"hash for a: %lu  b: %lu c: %lu", (unsigned long)[a hash], (unsigned long)[b hash], (unsigned long)[c hash]);

output:
  a == b: 1
  a == c: 0
  hash for a: 3952407433  b: 3952407433 c: 3952405511

这看起来正确吗?

最佳答案

你遇到了像(0.5 ± 0.015625)*1e-8这样的值的麻烦。坐标的绝对差小于公差,但舍入会导致不同的整数。
编辑:
这意味着两个对象可以被认为是相等的,但是具有不同的散列码。如果使用哈希映射,不一致的等式和哈希代码可能会带来严重问题。
解决方案是比较isEqual中每个对象的散列:

- (BOOL)isEqualToAGPoint:(AGPoint *)otherPoint
{
  if ([otherPoint hash] != [self hash])
    return NO;

  if (fabs(otherPoint->latitude - latitude) > 0.00000001)
    return NO;

  if (fabs(otherPoint->longitude - longitude) > 0.00000001)
    return NO;

  if (fabs(otherPoint->altitude - altitude) > 0.00000001)
    return NO;

  return YES;
}

09-30 17:15
查看更多