views:

550

answers:

1

I could use some help. After a few frustrating days of trial and error, I'm getting inconsistent results writing preferences to NSUserDefaults.

Here are the consecutive lines of code:

     NSLog(@"startTimer(): End Time defaults: %f\n", [defaults floatForKey:kEndTimeKey]);
 NSLog(@"startTimer(): new End Time: %f\n", endTime);
 [defaults setFloat:endTime forKey:kEndTimeKey];
 [defaults synchronize];
 NSLog(@"startTimer(): stored EndTimeKey: %f\n", [defaults floatForKey:kEndTimeKey]);

kEndTimeKey is a constant string.

As you can see I log the current value for the key, then I log the value I intend to store, synchronize, then re-read the stored value. Seems simple to me, but here's the debugger output:

2009-07-22 22:05:43.263 TimerTest3[1584:207] startTimer(): End Time defaults: 0.000000
2009-07-22 22:05:43.266 TimerTest3[1584:207] startTimer(): new End Time: 270018630.916571
2009-07-22 22:05:43.287 TimerTest3[1584:207] startTimer(): stored EndTimeKey: 270018624.000000

I see the original value 0, the intended value ending in 571, and the value read from the cache which is 6 seconds off.

I'm not sure where the new default came from. Any ideas? I get similar behavior on the device and on the simulator.

Thanks Brad

+1  A: 

How are you setting endTime. Is it a double? I am relatively certain this is not a NSUserDefaults issue, but a floating point math issue.

270018630.916571 is 16 decimal digits, which takes over ~48 bits of data to store the mantissa. A floating point is 32 bits, but 1 bit of that is a sign bit, 8 bits of exponent, and 23 bits of mantissa. That means the value you are seeing is way larger than a float can hold, and some amount of precision lost is expected. Even if you truncate it to 270018630 that still takes ~28 bits of percision to express, which means it has to be rounded in increments larger than a whole number.

Floating point numbers don't let you magically express larger numbers than ints with the same number of bits. They create the ability to store large numbers by varying the gap between numbers and using metadata (the exponent) to track it. Wikipedia has a decent explanation of how they work.

Louis Gerbarg
I believe you are correct. I was trying to store NSTimeIntervals which are defined as doubles. That explains why functionality was close in some cases, inconsistent in others, and fine for small numbers.