2010-11-17 3 views
0

Я пишу метод, который вычисляет средний временной интервал между рядом событий (в частности, нажатие кнопки в iPhone). Поскольку количество временных интервалов, которые я хочу усреднить, может меняться в течение жизненного цикла программы, я сохраняю показания времени в объекте с именем tapTimes типа NSMutableArray, поэтому мне не нужно беспокоиться об управлении размером массива.Хранение поплавков в NSMutableArray дает неожиданные результаты

Когда я храню показания времени как удваивается, все работает нормально (для простоты в следующем примере я заинтересован только в одном временном интервале):

CFAbsoluteTime time = CFAbsoluteTimeGetCurrent(); 
[tapTimes addObject:[NSNumber numberWithDouble:(double)time]]; 
[tapTimes removeObjectAtIndex:0]; 
double deltaT = [[tapTimes objectAtIndex:1] doubleValue] - [[tapTimes objectAtIndex:0] doubleValue]; 

Который, для нарезания каждый второй или так, дает (первое значение только первое время чтения с массива инициализируется нулями):

deltaT 311721948.947153 
deltaT 1.023200 
deltaT 1.080004 
deltaT 1.055961 
deltaT 1.087942 
deltaT 1.080074 

Однако, если хранить поплавки:

CFAbsoluteTime time = CFAbsoluteTimeGetCurrent(); 
[tapTimes addObject:[NSNumber numberWithFloat:(float)time]]; 
[tapTimes removeObjectAtIndex:0]; 
float deltaT = [[tapTimes objectAtIndex:1] floatValue] - [[tapTimes objectAtIndex:0] floatValue]; 

Тогда я получаю неожиданные результаты deltaT:

deltaT 311721760.000000 
deltaT 0.000000 
deltaT 0.000000 
deltaT 0.000000 
deltaT 0.000000 
deltaT 32.000000 
deltaT 0.000000 
deltaT 0.000000 
deltaT 0.000000 

Любая идея, что идет не так? (Я делаю первые шаги в Objective-c/какао, поэтому я надеюсь, что ответ не слишком тривиален :))

ответ

3

Проблема в том, что float не является достаточно точным, чтобы рассказать одну временную метку из временной метки через секунду. Придерживайтесь double; есть причина, по которой CFAbsoluteTime использует этот тип.

Вот демонстрация задачи в соответствии с 64-битной 10.6.4:

val: 311721760.000000 - val2: 311721761.000000 - (val2 - val): 1.000000 
v: 311721760.000000 - v2: 311721760.000000 - (v2 - v): 0.000000 

В первой строке используется double значения; val2 было создано путем добавления 1 в val. Во второй строке использованы значения float. Исходный код следующим образом:

//clang so_float.m -o so_float 
#import <stdio.h> 

int 
main(void) { 
    double val = 311721760.000000; 
    double val2 = val + 1.0; 
    fprintf(stderr, "val: %f - val2: %f - (val2 - val): %f\n", val, val2, val2 - val); 
    float v = val; 
    float v2 = val + 1.0; 
    fprintf(stderr, "v: %f - v2: %f - (v2 - v): %f\n", v, v2, v2 - v); 
    return 0; 
} 
+0

Просто проверяю я получил это право :: Если я использую (IEEE 754) одинарной точности поплавки, чтобы представить мой ** ** время чтения, у меня есть 23 бита разрешения для дробной части мантисса. так как 2^-23 составляет ок. 1е-7, я пересекаю границу разрешения «1 секунду» для показателя ок. 24, так как 2^24 ~ 1,6е7, что составляет ок. 6 месяцев (перевод секунд в месяцы) после контрольной даты 1 января 2001 года 00:00:00 GMT. Итак, я опаздываю на 9 лет после последнего шанса использовать поплавки с разрешением 1 секунду :) –

Смежные вопросы