Як додати два об'єкти NSNumber?


79

Тепер це має бути легко, але як можна підсумувати два NSNumber? Це як:

[one floatValue] + [two floatValue]

чи існує кращий спосіб?

Відповіді:


143

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

Наприклад:

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

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

Отже, якщо вам потрібно зберігати числа в диктах, використовуйте NSNumber, якщо вам потрібно передати щось, що може бути числом або рядком, у функцію, використовуйте NSNumber, але якщо ви просто хочете зробити математичну палицю зі скалярними типами C.


1
Я додав би, що якщо вам потрібно зберігати колекції чисел, для яких ви збираєтеся робити багато математики - можливо, ви дійсно хочете мати масив стилю С відповідного числового типу?
Kendall Helmstetter Gelner

Всякий раз, коли ви багато займаєтесь математикою, щоб використовувати скаляри, ви хочете використовувати об’єкти, коли вам потрібен поліморфізм або вони повинні поміститися в існуючі контейнери.
Луї Гербарг,

Правильним методом на NSNumber є 'numberWithFloat:' - можливо, це змінилося з часу відповіді.
Нік

Ви маєте рацію, геттер є floatValue, тому я зазвичай ввожу його в обох місцях, але stackoverflow не видає мені помилки компіляції. Виправлено
Луї Гербарг

2
@clopez: “Докторе, боляче, коли я це роблю”. NSNumber - коробковий тип для використання з контейнерами, а не для арифметики. Якщо ви займаєтеся арифметикою, використовуйте арифметичний тип.
Стівен Канон

49

NSDecimalNumber (підклас NSNumber ) містить усі потрібні вам смаколики:

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

...

Якщо продуктивність обчислень представляє інтерес, перетворіть на масив C ++ std :: vector або подібний.

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


Не могли б ви детальніше розказати, що ви маєте на увазі під "дуже нудним поєднанням кожного нового [] із видаленням []."?
jpswain

Скажімо так. У c, взагалі уникайте використання вказівника. Вся суть цілі-c полягає в тому, щоб нанести шар поверх C, про який НІКОЛИ не доведеться турбуватися. C - це не мова, яка повинна використовуватися безпосередньо. Це те, чим спочатку потрібно «керувати».
user4951

Після додавання двох NSDecimalNumbers, як перетворити NSDecimalNumberрезультат назад на NSNumber? (Це питання стосується додавання двох NSNumberс, а не додавання двох NSDecimalNumberс.)
ого

чому ви коли-небудь використовуєте масив C, коли у вас так чи інакше є вектор?
Джейк Лонг,

1
Чому ви хочете перетворити NSDecimalNumber назад у NSNumber? NSDecimalNumber - це NSNumber:@interface NSDecimalNumber : NSNumber
Стівен Фішер

12

Можна використовувати

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

Редагувати: Як спостерігав ohho , цей приклад стосується складання двох NSNumberекземплярів, які містять цілі значення. Якщо ви хочете скласти два NSNumber, що містять значення з плаваючою комою, вам слід зробити наступне:

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

У чому причина символу "@"? Я не впевнений, що розумію, що він робить у цьому контексті.
Mike Meyers

Ага. Я бачу зараз .... це буквар NSNumber, як описано тут: stackoverflow.com/a/11120371/35723
Mike Meyers

Так, @mikemeyers це буквальне , що компреси примітиви , як intі longчи це великий брат typedef« під ред NSIntegerв NSNumber об'єкти .
Немезида

integerValueусіки float. Як за цю відповідь можна проголосувати?
ohho,

@ohho це був простий приклад. Чому б у світі ви використовували, integerValueякщо хочете зберегти десяткову частину чисел?
Немезида

6

Поточна відповідь з найбільшою оцінкою призведе до важко діагностуються помилок та втрати точності через використання плаваючих знаків. Якщо ви виконуєте числові операції зі значеннями NSNumber, вам слід спочатку перетворити на NSDecimalNumber і замість цього виконувати операції з цими об'єктами.

З документації :

NSDecimalNumber, незмінний підклас NSNumber, забезпечує об'єктно-орієнтовану обгортку для виконання арифметики base-10. Екземпляр може представляти будь-яке число, яке може бути виражене як показник mantissa x 10 ^, де mantissa - це десяткове ціле число довжиною до 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]

У Swift 3:

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

0

Чому б не використовувати 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"

Ви також можете створити вираз NSE, який можна використовувати повторно для оцінки за допомогою різних аргументів, наприклад:

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]);
 }

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.