2009-01-17 18 views
43

Buduję aplikację, która musi wykonywać obliczenia na pieniądze.Jak korzystać z NSDecimalNumber?

Zastanawiam się, jak poprawnie używać NSDecimalNumber, szczególnie jak zainicjować go z liczb całkowitych, pływa pod & podwaja?

Znalazłem tylko łatwe w użyciu metody -decimalNumberWithString:. Te metody są zniechęceni -initWith... tak, że tylko lewy te z mantysy, ale nigdy w żadnej z 7 języków użyłem zanim ja trzeba, że ​​tak nie wiem, co tam umieścić ...

Odpowiedz

80

Czy NIE korzystanie NSNumber metody tworzenia obiektów +numberWith.... Zostały one zadeklarowane jako zwracające obiekty NSNumber i nie mają gwarancji, że będą działać jako instancje NSDecimalNumber.

Zostało to wyjaśnione w tym dokumencie: thread autorstwa Billa Bumgarnera, programisty w firmie Apple. Zachęcam Cię do zgłoszenia błędu w odniesieniu do tego zachowania, odwołując się do błędu rdar: // 6487304.

Alternatywą są wszystkie odpowiednie metody użyć, aby utworzyć NSDecimalNumber:

+ (NSDecimalNumber *)decimalNumberWithMantissa:(unsigned long long)mantissa 
        exponent:(short)exponent isNegative:(BOOL)flag; 
+ (NSDecimalNumber *)decimalNumberWithDecimal:(NSDecimal)dcm; 
+ (NSDecimalNumber *)decimalNumberWithString:(NSString *)numberValue; 
+ (NSDecimalNumber *)decimalNumberWithString:(NSString *)numberValue locale:(id)locale; 

+ (NSDecimalNumber *)zero; 
+ (NSDecimalNumber *)one; 
+ (NSDecimalNumber *)minimumDecimalNumber; 
+ (NSDecimalNumber *)maximumDecimalNumber; 
+ (NSDecimalNumber *)notANumber; 

Jeśli chcesz po prostu się NSDecimalNumber od A float lub int stałej try coś takiego:

NSDecimalNumber *dn = [NSDecimalNumber decimalNumberWithDecimal: 
          [[NSNumber numberWithFloat:2.75f] decimalValue]; 
+4

Dodatkowo, jak powiedział @orj poniżej, poprawne jest również użycie opcji '-initWithFloat:', '-initWithDouble:' i innych metod. Są one zadeklarowane jako zwracające "id", a ja właśnie zweryfikowaliśmy, że rzeczywiście zwracają 'NSDecimalNumber' na Snow Leopard. –

+2

+1 za wymienienie 'NSNumber''s' decimalValue'. Całkowicie tęskniłem za tą w dokumentach. –

+0

Może ktoś powinien zmienić tytuł na "Jak zrobić coś prostego niezwykle skomplikowanego". Mimo to dzięki za wyprostowanie rzeczy. – turingtested

6

Pod względem projektowania należy unikać konwersji wartości NSDecimalNumber lub NSDecimals na wartości int, float i double z tych samych powodów, dla których zalecane jest użycie NSDecimalNumbers: lo ss precyzji i binarnych zagadnień reprezentacji zmiennoprzecinkowej. Wiem, że czasami jest to nieuniknione (pobieranie danych z suwaka, wykonywanie obliczeń trygonometrycznych itp.), Ale powinieneś próbować pobierać dane od użytkowników jako NSStrings, a następnie użyć initWithString: locale: lub decimalNumberWithString: locale: aby wygenerować NSDecimalNumbers. Wykonaj całą swoją matematykę z NSDecimalNumbers i zwróć ich reprezentację użytkownikom lub zapisz je w SQLite (lub gdziekolwiek) jako opis ciągu za pomocą descriptionWithLocale :.

Jeśli masz do wejścia z int, float lub double, można zrobić coś jak następuje:

int myInt = 3; 
NSDecimalNumber *newDecimal = [NSDecimalNumber decimalNumberWithString:[NSString stringWithFormat:@"%d", myInt]]; 

lub można śledzić sugestię Ashleya, aby upewnić się, że jesteś bezpieczny w budowie dziesiętnych .

30

Prawidłowy sposób jest rzeczywiście to zrobić:

NSDecimalNumber *floatDecimal = [[[NSDecimalNumber alloc] initWithFloat:42.13f] autorelease]; 
NSDecimalNumber *doubleDecimal = [[[NSDecimalNumber alloc] initWithDouble:53.1234] autorelease]; 
NSDecimalNumber *intDecimal = [[[NSDecimalNumber alloc] initWithInt:53] autorelease]; 

NSLog(@"floatDecimal floatValue=%6.3f", [floatDecimal floatValue]); 
NSLog(@"doubleDecimal doubleValue=%6.3f", [doubleDecimal doubleValue]); 
NSLog(@"intDecimal intValue=%d", [intDecimal intValue]); 

Zobacz więcej informacji here.