2010-01-09 7 views
16

jestem przeprowadzenie szeregu obliczeń wykorzystujących NSDecimal i tworzę każdy NSDecimal struct stosując następujące techniki:Czy istnieje sposób na utworzenie NSDecimal bez używania NSNumber i tworzenia autoreleased obiektów?

[[NSNumber numberWithFloat:kFloatConstant] decimalValue] 

Używam NSDecimal aby unikać autoreleased NSDecimalNumber przedmiotów (jeśli używana jest podejście NSDecimalNumber do dokładnych obliczeń). Jednak wydaje się, że mechanizm tworzenia NSNumber zwraca także autouzupełnianie NSNumber, z którego wyodrębniana jest wartość dziesiętna.

Czy istnieje sposób na utworzenie numeru NSDecimal bez używania NSNumber i tworzenia autorejestrowanych obiektów?

+0

To naprawdę wydaje się 'NSDecimal' został zaprojektowany dla rzeczy o określonych zakresach precyzyjnych gdzie dokładny dokładność jest ważne, jak waluta, której zazwyczaj nie chcą konwertować ** ani do, ani z ** a 'float' lub' double' z powodu ryzyka utraty precyzji. Czy mógłbyś powiedzieć nam więcej o twoim przypadku użycia? –

Odpowiedz

27

Niestety, Apple nie zapewnia łatwych sposobów umieszczania wartości w strukturze NSDecimal. Sama definicja struct można znaleźć w nagłówku NSDecimal.h:

typedef struct { 
    signed int _exponent:8; 
    unsigned int _length:4;  // length == 0 && isNegative -> NaN 
    unsigned int _isNegative:1; 
    unsigned int _isCompact:1; 
    unsigned int _reserved:18; 
    unsigned short _mantissa[NSDecimalMaxSize]; 
} NSDecimal; 

ale nie wiem, że pójdę w kółko, próbując odwrócić inżynier jak kodowanym utrzymywania wartości. Podkreślenia na polach w strukturze wskazują, że są one prywatne i mogą ulec zmianie. Nie wyobrażam sobie, że wiele zmian zachodzi w niskopoziomowych funkcjach NSDecimal, ale denerwuję się, że w pewnym momencie coś się załamie.

Biorąc pod uwagę, że inicjowanie NSDecimal z liczby zmiennoprzecinkowej najlepiej zrobić w sposób, który opisujesz. Należy jednak pamiętać, że za każdym razem, gdy używasz wartości zmiennoprzecinkowej, tracisz uzyskaną dokładność za pomocą wartości NSDecimal i będziesz narażać się na błędy zmiennoprzecinkowe.

Zawsze pracuję tylko z NSDecimals w moich precyzyjnych obliczeniach, a także biorę i eksportuję NSStrings do wymiany tych wartości ze światem zewnętrznym. Aby utworzyć NSDecimal oparciu o NSString, można stosować metodę bierzemy w Core Plot framework:

NSDecimal CPDecimalFromString(NSString *stringRepresentation) 
{ 
    NSDecimal result; 
    NSScanner *theScanner = [[NSScanner alloc] initWithString:stringRepresentation]; 
    [theScanner scanDecimal:&result]; 
    [theScanner release]; 

    return result; 
} 

Korzystanie NSScanner zamiast NSDecimalNumber -initWithString:locale: jest o 90% szybszy w moich benchmarków.

+0

Klasa NSDecimal jest tak źle rozumiana, a to dlatego, że jest tak sprzeczna z intuicją. Dlaczego jabłko sprawiło, że był tak przyjazny dla programistów? Jakie są alternatywy dla NSDecimal? –

+3

@AndrewS - Po pierwsze, NSDecimal nie jest klasą, ale strukturą, więc musi być traktowany trochę inaczej niż standardowe obiekty. Złożoność w NSDecimal funkcji obsługi wydaje się wynikać z chęci, aby je jak najszybciej. Zauważ, że przechodzą one przez odniesienie do tych funkcji, jako tylko jedną optymalizację. Nie ma jednak wymówki, aby nie mieć łatwego konstruktora dla NSDecimals. –

+0

Czy istnieje bardziej prymitywny dziesiętny jak NSInteger? –

2

odpowiedzieć na „bez autoreleased obiektów” części, po prostu:

NSDecimalNumber *intermediateNumber = [[NSDecimalNumber alloc] initWithFloat:kFloatConstant]; 
NSDecimal decimal = [intermediateNumber decimalValue]; 
[intermediateNumber release]; 
+0

Problem w tym przypadku polega nie tyle na tym, że obiekt jest autoreleased, lecz na unikaniu przydzielania go na samym początku. Każda alokacja numeru NSDecimalNumber, autoreleased lub nie, będzie wolniejsza niż w przypadku struktury NSDecimal: http://stackoverflow.com/questions/1704504/what-is-the-right-choice-between-nsdecimal-nsdecimalnumber-cnnumber/ 1710277 # 1710277. W tworzeniu i zniszczeniu tych obiektów istnieje znaczny nadmiar. Zakładasz również, że zaczynają się od wartości float, co, miejmy nadzieję, nie będzie miało miejsca w przypadku NSDecimals i NSDecimalNumbers. –

+0

Ponadto, prawdopodobnie nie chcesz używać -initWithFloat: z powodów opisanych tutaj: http://stackoverflow.com/a/5304993/19679 –

+0

@BradLarson Dlatego właśnie przedrostka z odpowiedzią "Odpowiedź" bez autoreleased część obiektów ". –

Powiązane problemy