Jak dodać dwa obiekty NSNumber?

79

To musi być łatwe, ale jak zsumować dwa NSNumber? Jest jak:

[one floatValue] + [two floatValue]

czy istnieje lepszy sposób?

mamcx
źródło

Odpowiedzi:

143

Nie ma lepszego sposobu, ale naprawdę nie powinieneś tego robić, jeśli możesz tego uniknąć. NSNumberistnieje jako opakowanie dla liczb skalarnych, dzięki czemu można je przechowywać w kolekcjach i przekazywać je polimorficznie z innymi NSObjects. Nie są tak naprawdę używane do przechowywania liczb w rzeczywistej matematyce. Jeśli wykonujesz na nich obliczenia matematyczne, jest to znacznie wolniejsze niż wykonywanie operacji na samych skalarach, dlatego prawdopodobnie nie ma na to wygodnych metod.

Na przykład:

NSNumber *sum = [NSNumber numberWithFloat:([one floatValue] + [two floatValue])];

Wydmuchuje co najmniej 21 instrukcji dotyczących wysyłek wiadomości i ile kodu zajmą metody, aby rozpakować i zmienić wartości (prawdopodobnie kilkaset), aby wykonać jedną instrukcję matematyczną.

Więc jeśli chcesz przechowywać liczby w dyktach, użyj znaku an NSNumber, jeśli chcesz przekazać do funkcji coś, co może być liczbą lub ciągiem znaków, użyj znaku NSNumber, ale jeśli chcesz po prostu używać matematyki trzymaj się skalarnych typów C.

Louis Gerbarg
źródło
1
Dodałbym, że jeśli chcesz przechowywać zbiory liczb, dla których zamierzasz dużo matematykować - może naprawdę potrzebujesz tablicy w stylu C o odpowiednim typie liczbowym?
Kendall Helmstetter Gelner
Ilekroć robisz dużo matematyki, chcesz użyć skalarów, chcesz użyć obiektów, gdy potrzebujesz polimorfizmu lub muszą pasować do istniejących kontenerów.
Louis Gerbarg
Właściwa metoda na NSNumber to „numberWithFloat:” - być może to się zmieniło od czasu udzielenia odpowiedzi.
Nick
Masz rację, getter to floatValue, więc zwykle wpisuję go w obu miejscach, ale przepełnienie stosu nie daje mi błędu kompilacji. Naprawiono
Louis Gerbarg
2
@clopez: „Doktorze, boli, kiedy to robię”. NSNumber jest typem pudełkowym do użytku z kontenerami, a nie do arytmetyki. Jeśli robisz arytmetykę, użyj typu arytmetycznego.
Stephen Canon
49

NSDecimalNumber (podklasa NSNumber ) zawiera wszystkie gadżety, których szukasz:

– decimalNumberByAdding:
– decimalNumberBySubtracting:
– decimalNumberByMultiplyingBy:
– decimalNumberByDividingBy:
– decimalNumberByRaisingToPower:

...

Jeśli interesuje Cię wydajność obliczeniowa, przekonwertuj na tablicę std :: vector w C ++ lub podobną.

Teraz już nigdy nie używam C-Arrays; zbyt łatwo ulega awarii przy użyciu niewłaściwego indeksu lub wskaźnika. I bardzo żmudne parowanie każdego nowego [] z delete [].

Semmel
źródło
Czy mógłbyś wyjaśnić, co masz na myśli, mówiąc „bardzo żmudne parowanie każdego nowego [] z usuwaniem []”?
jpswain
Ujmijmy to w ten sposób. W c, w ogóle unikaj używania wskaźnika. Celem celu-c jest nałożenie warstwy na C, o którą NIGDY nie musisz się martwić. C nie jest językiem, którego można używać bezpośrednio. To coś, czym należy najpierw „zarządzać”.
user4951
Po dodaniu dwóch NSDecimalNumbers, jak przekonwertować NSDecimalNumberwynik z powrotem na NSNumber? (To pytanie dotyczy dodawania dwóch NSNumbers, a nie dodawania dwóch NSDecimalNumber.)
ohho
dlaczego miałbyś kiedykolwiek używać tablicy C, skoro i tak masz wektor?
Jake Long
1
Dlaczego chcesz przekonwertować NSDecimalNumber z powrotem na NSNumber? NSDecimalNumber to NSNumber:@interface NSDecimalNumber : NSNumber
Steven Fisher,
12

Możesz użyć

NSNumber *sum = @([first integerValue] + [second integerValue]);

Edycja: jak zaobserwował Ohho , ten przykład służy do dodawania dwóch NSNumberinstancji, które przechowują wartości całkowite. Jeśli chcesz dodać dwa NSNumber, które przechowują wartości zmiennoprzecinkowe, wykonaj następujące czynności:

NSNumber *sum = @([first floatValue] + [second floatValue]);
Nemezys
źródło
Jaki jest powód pojawienia się symbolu „@”? Nie jestem pewien, czy rozumiem, co robi w tym kontekście.
Mike Meyers
Ach. Widzę teraz ... to literał NSNumber, jak opisano tutaj: stackoverflow.com/a/11120371/35723
Mike Meyers
Tak, @mikemeyers to dosłowne, która otacza prymitywy jak intlub longczy jest to wielki brat typedef„ed NSIntegerdo NSNumber obiektów .
nemesis,
integerValueobcina float. Jak można głosować pozytywnie na tę odpowiedź?
ohho
@ohho to był prosty przykład. Dlaczego na świecie miałbyś używać, integerValuejeśli chcesz zachować dziesiętną część liczb?
nemesis
6

Obecna, najczęściej wybierana odpowiedź doprowadzi do trudnych do zdiagnozowania błędów i utraty precyzji z powodu użycia pływaków. Jeśli wykonujesz operacje liczbowe na wartościach NSNumber, powinieneś najpierw przekonwertować na NSDecimalNumber i zamiast tego wykonać operacje na tych obiektach.

Z dokumentacji :

NSDecimalNumber, niezmienna podklasa NSNumber, zapewnia zorientowaną obiektowo otokę do wykonywania arytmetyki na podstawie 10. Instancja może reprezentować dowolną liczbę, którą można wyrazić jako mantysa x 10 ^ wykładnik, gdzie mantysa jest dziesiętną liczbą całkowitą o długości do 38 cyfr, a wykładnikiem jest liczbą całkowitą od –128 do 127.

Dlatego powinieneś przekonwertować swoje wystąpienia NSNumber na NSDecimalNumbers w drodze [NSNumber decimalValue], wykonać dowolną arytmetykę, a następnie przypisać z powrotem do NSNumber, kiedy skończysz.

W celu C:

NSDecimalNumber *a = [NSDecimalNumber decimalNumberWithDecimal:one.decimalValue]
NSDecimalNumber *b = [NSDecimalNumber decimalNumberWithDecimal:two.decimalValue]
NSNumber *result = [a decimalNumberByAdding:b]

W Swift 3:

let a = NSDecimalNumber(decimal: one.decimalValue)
let b = NSDecimalNumber(decimal: two.decimalValue)
let result: NSNumber = a.adding(b)
Dan Loewenherz
źródło
0

Dlaczego nie używać NSxEpression?

NSNumber *x = @(4.5), *y = @(-2);

NSExpression *ex = [NSExpression expressionWithFormat:@"(%@ + %@)", x, y];
NSNumber *result = [ex expressionValueWithObject:nil context:nil];

NSLog(@"%@",result); // will print out "2.5"

Możesz również zbudować NSExpression, którego można ponownie użyć do oceny z różnymi argumentami, na przykład:

NSExpression *expr = [NSExpression expressionWithFormat: @"(X+Y)"];
NSDictionary *parameters = [NSDictionary dictionaryWithObjectsAndKeys:x, @"X", y, @"Y", nil];
NSLog(@"%@", [expr expressionValueWithObject:parameters context:nil]);

Na przykład możemy zapętlić obliczenie tego samego przeanalizowanego wyrażenia, za każdym razem z inną wartością „Y”:

 for (float f=20; f<30; f+=2.0) {
    NSDictionary *parameters = [NSDictionary dictionaryWithObjectsAndKeys:x, @"X", @(f), @"Y", nil];
    NSLog(@"%@", [expr expressionValueWithObject:parameters context:nil]);
 }
Motti Shneor
źródło
-1

W Swift możesz uzyskać tę funkcjonalność, korzystając z biblioteki Bolt_Swift https://github.com/williamFalcon/Bolt_Swift .

Przykład:

  var num1 = NSNumber(integer: 20)
  var num2 = NSNumber(integer: 25)
  print(num1+num2) //prints 45
William Falcon
źródło