我有一个存储纬度/经度/海拔高度的对象,需要可靠和快速 -hash
和isEqual
实施。我使用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 :(得分:1)
您遇到像(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;
}