У меня есть объект, который хранит широту / долготу / высоту, и мне нужны надежные и быстрые -hash
и isEqual
реализации. Я использую double
для хранения всех примитивов.
Принятый ответ для Рекомендации по переопределению isEqual: хеш выглядит хорошо, но в нем говорится только о 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
Это выглядит правильно?