iPhone - Съхраняване на двойна стойност в NSDictionary само със 7 знака след десетичната запетая като тип число

Имам PList, който съдържа речник с някои десетични стойности като 10.1234567, съхранени като тип номер (таг).
В моето приложение чета този plist и манипулирам тези стойности като NSNumber (стойности от двоен тип) с персонализиран клас и неговите аксесоари:

@interface
...
@property(nonatomic, assign) NSNumber* someValue;
...
@end

@implementation
...
- (NSNumber*) someValue { return [self.dict objectForKey:@"val"]; }
- (void) setSomeValue:(NSNumber*)val { [self.dict setValue:val forKey:@"val"]; }
...
@end

Тогава в някои случаи записвам обратно на диска plist.

Забелязах преди няколко часа, че тези стойности, да речем, бяха преобразувани и сега са нещо като 10,123456699999999. Всички тях ! ...

Уау, не очаквах тази промяна.

Е, опитах се да овладея проблема с промяната на аксесоарите с много неща, като например това:

- (NSNumber*) someValue { return [self.dict objectForKey:@"val"]; }
- (void) setSomeValue:(NSNumber*)val { [self.dict setValue:
                                              [NSNumber numberWithDouble:[[NSString stringWithFormat:@"%.7lf", [val doubleValue]] doubleValue]] 
                                                          forKey:@"val"]; }

Но не мога да запазя тези стойности с първоначалните им 7 знака след десетичната запетая.

Как мога да направя, за да напиша само 7 знака след десетичната запетая, без да се налага да използвам нещо друго освен числов тип за полето в речника (имам предвид, че използването на низ не би било добро решение)?

Създаването на plist файла беше направено на ръка, с няколко часа писане, въвеждане на тези 7 десетични стойности във всяко поле и те не бяха "преобразувани" в този момент. Те бяха съхранени със 7 знак след десетичната запетая. Така че предполагам, че има решение да запазите тези 7 знака след десетичната запетая, когато ги записвате обратно от програма.


person Oliver    schedule 24.09.2011    source източник


Отговори (3)


Добре дошли в прекрасния свят на числата с плаваща запетая. Ако искате да използвате стойности с плаваща запетая, трябва да сте подготвени за факта, че стойностите с плаваща запетая само рядко са точно тези стойности, които искате, но по-често малко повече или по-малко.

Можете да използвате цяло число (мащабирано, ако е необходимо) или да конвертирате в символна форма. Има клас NSDecimalNumber, който би бил точен, но не се вписва в схемата NSNumber и, доколкото ми е известно, няма да работи с JSON и други, ако това е необходимо. Въпреки това би трябвало да работи като речников ключ, бих си помислил.

person Hot Licks    schedule 24.09.2011
comment
в допълнение: вашето (на Оливър) число изглежда лесно в десетичната система, но не и в двоичната! Разгледайте тази връзка (след вмъкване на вашето число в третия ред, той изчислява плаващата запетая и я преобразува обратно в десетична: h-schmidt.net/FloatApplet/IEEE754.html - person thomas; 25.09.2011
comment
@Daniel R Hicks: Това общ отговор ли е? Нямам нужда от общ отговор. Знам какви са свойствата на числата с плаваща запетая, десетичната / двоичната концепция, ... Трябва да съхраня 7 десетично число (и не още едно) в речник в PLIST файл, който съдържа това 7 десетично число, преди да го прочета, и може да го управлява, без да се налага да добавя xxx безполезни десетични знаци. - person Oliver; 25.09.2011
comment
@Oliver -- Избрахте да използвате числа с плаваща запетая и трябва да живеете с последствията. - person Hot Licks; 25.09.2011

Може да искате да разгледате IEEE стандарт 754-2008 и да освежите двоичния си файл. Компютрите не съхраняват вътрешно плаваща запетая, използвайки базови 10 цифри от 0 до 9; по-скоро те използват двоични числа 0 и 1. Ако подадете 10.1234567 на компютър и го помолите да съхрани това число като 64-битово двойно число с плаваща запетая, най-близкото, което може да стигне до тази стойност, ще бъде нещо като 10.1234566999999. ... че виждате. И това число всъщност е нещо като 1001.00111111001101011011011 (т.е. 10 + 2071259/16777216).

Ако искате да съхраните точно 7 десетични цифри, запазете необработените знаци като низ. Или измислете някакъв друг начин за съхраняване на цифри с основа 10, вместо двоични цифри с основа 2.

Ако искате да конвертирате число с плаваща запетая в текст само със 7 цифри на точност, можете да използвате:

NSString* output = [NSString stringWithFormat:@"%.7d",myFloat];
person AndrewS    schedule 24.09.2011
comment
имаш предвид .7f :-) ? Знам как да го свържа като струна. Но... дайте този низ на NSDictionary с setValue и той ще го съхрани като тип String, а не Number one. Не искам да конвертирам типове, просто искам да запазя стойност със същата дължина, с която съм я прочел. - person Oliver; 25.09.2011

Използвайте NSNumberFormatter, когато извличате NSNumber от plist и трябва да работи:

NSNumberFormatter *nf = [[[NSNumberFormatter alloc] init] autorelease];
[nf setMaximumFractionDigits:7];
NSNumber *yourNumber = [nf numberFromString:[[self someValue] stringValue]];
person Herz Rod    schedule 24.09.2011
comment
Опитайте да отпечатате [[self someValue] stringValue] и вижте какво има - person Herz Rod; 25.09.2011
comment
@herz -- След като върнете стойността обратно в NSNumber, тя отново става стойност с плаваща запетая. (Или в този случай би било безсмислена стойност?) - person Hot Licks; 25.09.2011
comment
Но NSNumberFormatter трябва да форматира за всичко, което искате - person Herz Rod; 25.09.2011