Как добавить два объекта NSNumber?

Теперь это должно быть легко, но как сложить два NSNumber? Как:

[one floatValue] + [two floatValue]

или существует лучший способ?


person mamcx    schedule 29.01.2009    source источник


Ответы (6)


На самом деле нет лучшего способа, но вам действительно не следует этого делать, если вы можете этого избежать. NSNumber существует как оболочка для скалярных чисел, поэтому вы можете хранить их в коллекциях и полиморфно передавать с другими NSObjects. На самом деле они не используются для хранения чисел в реальной математике. Если вы выполняете математику с ними, это намного медленнее, чем выполнение операции только со скалярами, поэтому, вероятно, для этого нет удобных методов.

Например:

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

Выполняется как минимум 21 инструкция по отправке сообщений, и сколько бы кода ни потребовалось методам для распаковки и переупаковки значений (вероятно, несколько сотен), чтобы выполнить 1 математическую инструкцию.

Поэтому, если вам нужно хранить числа в словарях, используйте NSNumber, если вам нужно передать что-то, что может быть числом или строкой, в функцию, используйте NSNumber, но если вы просто хотите выполнять математические операции со скалярными типами C.

person Louis Gerbarg    schedule 30.01.2009
comment
Я бы добавил, что если вам нужно хранить наборы чисел, для которых вы собираетесь выполнять много математических операций, возможно, вам действительно нужен массив в стиле C правильного числового типа? - person Kendall Helmstetter Gelner; 30.01.2009
comment
Всякий раз, когда вы выполняете много математических операций, вы хотите использовать скаляры, вы хотите использовать объекты, когда вам нужен полиморфизм или они должны поместиться в существующие контейнеры. - person Louis Gerbarg; 30.01.2009
comment
Правильный метод для NSNumber — «numberWithFloat:» — возможно, это изменилось с момента ответа. - person Nick; 30.11.2010
comment
Вы правы, получателем является floatValue, поэтому я обычно набираю его в обоих местах, но stackoverflow не дает мне ошибки компиляции. Фиксированный - person Louis Gerbarg; 02.12.2010
comment
Если вы посмотрите, я ответил на вопрос более 5 лет назад, задолго до того, как были добавлены литералы. - person Louis Gerbarg; 06.04.2014
comment
@clopez: «Доктор, мне больно, когда я это делаю». NSNumber — это коробочный тип для использования с контейнерами, а не для арифметики. Если вы занимаетесь арифметикой, используйте арифметический тип. - person Stephen Canon; 08.04.2014
comment
Конечно, это медленно, но что я могу сделать, если использую CoreData? - person Fidel López; 12.06.2015
comment
Это в первую очередь - ложь - о NSNumbers. Существует несколько механик, позволяющих напрямую манипулировать и вычислять NSNumbers. первые два, которые приходят на ум, — это NSDecimalNumber (подкласс NSNumber), который поддерживает вычисления, и NSExpression, который оценивает произвольно сложные выражения, где аргументы могут быть объектами NSNumber. - person Motti Shneor; 20.02.2019

NSDecimalNumber (подкласс NSNumber) есть все, что вы ищете:

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

...

Если вас интересует производительность вычислений, конвертируйте в массив С++ std::vector или тому подобное.

Теперь я больше никогда не использую C-Arrays; слишком легко сбой, используя неправильный индекс или указатель. И очень утомительно соединять каждый новый [] с delete[].

person Semmel    schedule 23.06.2011
comment
Не могли бы вы уточнить, что вы подразумеваете под очень утомительным связыванием каждого нового [] с удалением [].? - person jpswain; 12.08.2011
comment
Скажем так. В c вообще избегайте использования указателя. Весь смысл Objective-C в том, чтобы поместить слой поверх C, о котором вам НИКОГДА не придется беспокоиться. C не является языком, который можно использовать напрямую. Это то, чем нужно управлять в первую очередь. - person user4951; 29.05.2012
comment
После добавления двух NSDecimalNumber как преобразовать результат NSDecimalNumber обратно в NSNumber? (Этот вопрос касается добавления двух NSNumber, а не добавления двух NSDecimalNumber.) - person ohho; 05.02.2013
comment
зачем вам когда-либо использовать массив C, когда у вас есть вектор? - person Jake Long; 30.05.2013
comment
Почему вы хотите преобразовать NSDecimalNumber обратно в NSNumber? NSDecimalNumber является NSNumber: @interface NSDecimalNumber : NSNumber - person Steven Fisher; 06.12.2013
comment
Не могу поверить, что у этого комментария 38 голосов. Либо объясните, почему C++ std::vector лучше, либо опустите его. В настоящее время это кажется предвзятым. - person Austin; 14.05.2015
comment
NSDecimalNumber является подклассом NSNumber @ohho - person Oritm; 27.07.2015
comment
Какое отношение массивы имеют к вопросу или к вашему ответу? - person Motti Shneor; 20.02.2019

Ты можешь использовать

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

Изменить: как заметил ohho, этот пример предназначен для сложения двух экземпляров NSNumber, которые содержат целочисленные значения. Если вы хотите сложить два NSNumber, которые содержат значения с плавающей запятой, вы должны сделать следующее:

NSNumber *sum = @([first floatValue] + [second floatValue]);
person nemesis    schedule 14.11.2013
comment
В чем причина символа @? Я не уверен, что понимаю, что он делает в этом контексте. - person Mike Meyers; 17.12.2013
comment
Ах. Теперь я вижу.... это литерал NSNumber, как описано здесь: stackoverflow.com/a/11120371/35723 - person Mike Meyers; 17.12.2013
comment
Да, @mikemeyers, это литерал, который оборачивает такие примитивы, как int или long, или его старший брат typedef'ed NSInteger в NSNumber объекты. - person nemesis; 07.01.2014
comment
integerValue усекает float. Как за этот ответ можно проголосовать? - person ohho; 08.04.2014
comment
@ohho это был простой пример. Зачем вам использовать integerValue, если вы хотите сохранить десятичную часть чисел? - person nemesis; 08.04.2014

Текущий ответ с наибольшим количеством голосов приведет к труднодиагностируемым ошибкам и потере точности из-за использования поплавки. Если вы выполняете числовые операции со значениями NSNumber, вы должны сначала преобразовать в NSDecimalNumber и вместо этого выполнять операции с этими объектами.

Из документации:

NSDecimalNumber, неизменяемый подкласс NSNumber, предоставляет объектно-ориентированную оболочку для выполнения десятичной арифметики. Экземпляр может представлять любое число, которое может быть выражено как мантисса x 10 ^ показатель степени, где мантисса — это десятичное целое число длиной до 38 цифр, а показатель степени — целое число от –128 до 127.

Следовательно, вы должны преобразовать свои экземпляры NSNumber в NSDecimalNumbers с помощью [NSNumber decimalValue], выполнить любую арифметику, которую вы хотите, а затем присвоить обратно NSNumber, когда закончите.

В цели-C:

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

В Свифт 3:

let a = NSDecimalNumber(decimal: one.decimalValue)
let b = NSDecimalNumber(decimal: two.decimalValue)
let result: NSNumber = a.adding(b)
person dwlz    schedule 17.01.2017

Почему бы не использовать 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"

Вы также можете создать NSExpression, который можно повторно использовать для оценки с различными аргументами, например:

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

Например, мы можем зациклить оценку одного и того же проанализированного выражения, каждый раз с другим значением «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]);
 }
person Motti Shneor    schedule 20.02.2019

В Swift вы можете получить эту функциональность с помощью библиотеки Bolt_Swift https://github.com/williamFalcon/Bolt_Swift. .

Пример:

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