Wie füge ich zwei NSNumber-Objekte hinzu?

79

Das muss einfach sein, aber wie kann man zwei summieren NSNumber? Ist wie:

[one floatValue] + [two floatValue]

oder gibt es einen besseren Weg?

mamcx
quelle

Antworten:

142

Es gibt keinen wirklich besseren Weg, aber Sie sollten dies wirklich nicht tun, wenn Sie es vermeiden können. NSNumberexistiert als Wrapper für skalare Zahlen, sodass Sie sie in Sammlungen speichern und polymorph mit anderen übergeben können NSObjects. Sie werden nicht wirklich verwendet, um Zahlen in der tatsächlichen Mathematik zu speichern. Wenn Sie mit ihnen rechnen, ist dies viel langsamer als das Ausführen der Operation nur für die Skalare, weshalb es wahrscheinlich keine praktischen Methoden dafür gibt.

Zum Beispiel:

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

Bläst mindestens 21 Anweisungen für Nachrichtenversendungen und wie viel Code die Methoden benötigen, um die zu entpacken und die Werte (wahrscheinlich einige hundert) neu zu verpacken, um 1 Befehl im Wert von Mathematik auszuführen.

Wenn Sie also Zahlen in Diktaten speichern müssen, verwenden Sie eine NSNumber, wenn Sie etwas, das eine Zahl oder eine Zeichenfolge sein kann, an eine Funktion übergeben müssen, verwenden Sie eine NSNumber, aber wenn Sie nur Mathe-Stick mit skalaren C-Typen ausführen möchten.

Louis Gerbarg
quelle
1
Ich würde das hinzufügen, wenn Sie Sammlungen von Zahlen speichern müssen, für die Sie viel rechnen möchten - vielleicht möchten Sie wirklich ein Array im C-Stil vom richtigen numerischen Typ?
Kendall Helmstetter Gelner
Wann immer Sie viel rechnen, möchten Sie die Skalare verwenden, Sie möchten die Objekte verwenden, wenn Sie Polymorphismus benötigen oder sie in vorhandene Container passen müssen.
Louis Gerbarg
Die richtige Methode für NSNumber ist 'numberWithFloat:' - möglicherweise hat sich dies seit dem Zeitpunkt der Beantwortung geändert.
Nick
Sie haben Recht, der Getter ist floatValue, daher tippe ich ihn gewöhnlich an beiden Stellen ein, aber der Stapelüberlauf gibt mir keinen Kompilierungsfehler. Feste
Louis Gerbarg
2
@clopez: "Doktor, es tut weh, wenn ich das tue." NSNumber ist ein Box-Typ für die Verwendung mit Containern, nicht für die Arithmetik. Wenn Sie rechnen, verwenden Sie einen arithmetischen Typ.
Stephen Canon
48

NSDecimalNumber (Unterklasse von NSNumber ) bietet alle Extras, die Sie suchen:

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

...

Wenn die Rechenleistung von Interesse ist, konvertieren Sie sie in das C ++ - Array std :: vector oder ähnliches.

Jetzt benutze ich nie mehr C-Arrays; Es ist zu leicht, mit einem falschen Index oder Zeiger zum Absturz zu kommen. Und sehr mühsam, jedes neue [] mit delete [] zu koppeln.

Semmel
quelle
Könnten Sie näher erläutern, was Sie unter "sehr mühsam, jedes neue [] mit delete [] zu koppeln" verstehen?
Jpswain
Sagen wir mal so. Vermeiden Sie in c die Verwendung eines Zeigers. Der springende Punkt bei Ziel-c ist, eine Ebene auf C zu legen, über die Sie sich NIEMALS Sorgen machen müssen. C ist keine Sprache, die direkt verwendet werden kann. Es ist etwas, das zuerst "verwaltet" werden muss.
user4951
NSDecimalNumberWie konvertiere NSDecimalNumberich das Ergebnis nach dem Hinzufügen von zwei s wieder in NSNumber? (Diese Frage ist über das Hinzufügen von zwei NSNumbers, nicht zwei NSDecimalNumbers hinzufügen .)
ohho
Warum sollten Sie jemals ein C-Array verwenden, wenn Sie sowieso einen Vektor haben?
Jake Long
1
Warum sollten Sie eine NSDecimalNumber wieder in eine NSNumber konvertieren? Eine NSDecimalNumber ist eine NSNumber:@interface NSDecimalNumber : NSNumber
Steven Fisher
12

Sie können verwenden

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

Bearbeiten: Wie von ohho beobachtet , dient dieses Beispiel zum Addieren von zwei NSNumberInstanzen, die ganzzahlige Werte enthalten. Wenn Sie zwei addieren möchten NSNumber, die Gleitkommawerte enthalten, sollten Sie Folgendes tun:

NSNumber *sum = @([first floatValue] + [second floatValue]);
Nemesis
quelle
Was ist der Grund für das "@" Symbol? Ich bin mir nicht sicher, ob ich verstehe, was es in diesem Zusammenhang tut.
Mike Meyers
Ah. Ich sehe jetzt ... es ist ein NSNumber-Literal, wie hier beschrieben: stackoverflow.com/a/11120371/35723
Mike Meyers
Ja, @mikemeyers es ist die wörtliche dass Wraps Primitiven , wie intoder longoder es ist großer Bruder typedef‚ed NSIntegerin NSNumber Objekte .
Erzfeind
integerValueschneidet ab float. Wie kann diese Antwort positiv bewertet werden?
Ohho
@ohho das war ein einfaches Beispiel. Warum in aller Welt würden Sie verwenden, integerValuewenn Sie den Dezimalteil der Zahlen beibehalten möchten?
Nemesis
6

Die derzeit am häufigsten gewählte Antwort wird zu schwer zu diagnostizierenden Fehlern und Präzisionsverlusten aufgrund der Verwendung von Floats führen. Wenn Sie Zahlenoperationen für NSNumber-Werte ausführen, sollten Sie zuerst in NSDecimalNumber konvertieren und stattdessen Operationen mit diesen Objekten ausführen.

Aus der Dokumentation :

NSDecimalNumber, eine unveränderliche Unterklasse von NSNumber, bietet einen objektorientierten Wrapper für die Basis-10-Arithmetik. Eine Instanz kann eine beliebige Zahl darstellen, die als Mantisse x 10 ^ Exponent ausgedrückt werden kann, wobei Mantisse eine bis zu 38 Stellen lange Dezimalzahl und Exponent eine Ganzzahl von –128 bis 127 ist.

Daher sollten Sie Ihre NSNumber-Instanzen in NSDecimalNumbers konvertieren [NSNumber decimalValue], eine beliebige Arithmetik ausführen und sie dann einer NSNumber zuweisen, wenn Sie fertig sind.

In Ziel-C:

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

In Swift 3:

let a = NSDecimalNumber(decimal: one.decimalValue)
let b = NSDecimalNumber(decimal: two.decimalValue)
let result: NSNumber = a.adding(b)
Dan Loewenherz
quelle
0

Warum nicht verwenden 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"

Sie können auch einen NSExpression erstellen, der zur Auswertung mit verschiedenen Argumenten wie folgt wiederverwendet werden kann:

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

Zum Beispiel können wir den gleichen analysierten Ausdruck jedes Mal mit einem anderen "Y" -Wert in einer Schleife auswerten:

 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
quelle
-1

In Swift können Sie diese Funktionalität mithilfe der Bolt_Swift-Bibliothek https://github.com/williamFalcon/Bolt_Swift erhalten .

Beispiel:

  var num1 = NSNumber(integer: 20)
  var num2 = NSNumber(integer: 25)
  print(num1+num2) //prints 45
William Falcon
quelle