NSNumber Расчеты и точность? - PullRequest
3 голосов
/ 25 февраля 2010

Два быстрых вопроса, если можно, вот как мне взять два объекта NSNumber, выполнить вычисления и получить результат, который также является NSNumber?

NSNumber *flux = [[NSNumber alloc] initWithDouble:100.0];
NSNumber *mass = [[NSNumber alloc] initWithDouble:3];

double intermediate = [flux doubleValue] / [mass doubleValue];
NSLog(@"INTER : %.20f", intermediate);

NSNumber *result = [[NSNumber alloc] initWithDouble:intermediate];
NSLog(@"RESULT: %@", result);

...
...

[flux release];
[mass release];
[result release];

Также, глядя на результаты в консоли от NSLog, есть ли потеря точности? Я бы предположил, что нет, и то, что я вижу, это просто отображение точности, но просто любопытно?

INTER : 33.33333333333333570181
RESULT: 33.33333333333334

1007 * Гэри *

Ответы [ 4 ]

14 голосов
/ 25 февраля 2010

(касается вашего вопроса, но связано)

NSNumber не предназначен для выполнения математики по основанию-10. Это в основном там, чтобы обернуть и хранить числовые значения. Если вам нужно заняться реальной математикой, вы должны использовать NSDecimal.

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

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

Так что, если у вас есть какие-либо сомнения по поводу точности, используйте NSDecimal вместо NSNumber. NSDecimal предназначен для выполнения точных расчетов.

Edit01:

... как мне взять два NSNumber объекты, выполняющие расчет и в конечном итоге с результат, который также является NSNumber?

Строго говоря, вы не должны использовать NSNumber для расчетов. Вы заметите, что NSNumber не имеет специальных методов для математики. Вы должны преобразовать в скаляр, а затем снова вернуться к объекту. Это приводит к потере точности, и точность может изменяться в зависимости от аппаратного обеспечения или определений скаляров.

NSDecimal, напротив, может точно представлять очень точные числа, потому что оно содержит их абстрактно. Он имеет специальные методы для выполнения точных математических операций.

Также смотрим на результаты в консоли от NSLog, есть ли потеря точность

Да, потеря математической точности выходит за рамки простого форматирования. Скаляры имеют различную точность в зависимости от их типа и размера числа, которое они хранят. При больших величинах это вызывает проблемы с точностью. Если вы смешаете типы, скажем, NSInteger и NSUInteger, вы получите максимальную точность NSInteger.

Вы также сталкиваетесь со всеми старыми проблемами использования скаляров.

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

NSDecimal освобождает вас от всех этих возможных источников ошибок. Это делает точные математические вычисления до величин, намного превышающих то, что кто-либо использовал бы в реальном мире.

Я повторяю: если важна точность, не используйте NSNumber или скаляр.

4 голосов
/ 25 февраля 2010

Внутренне NSNumber будет форматировать свое содержимое с :

  • двойной: %0.16g
  • float: %0.7g

Но вы указываете использовать 20 цифр после десятичной точки, что, безусловно, не соответствует описанию.

Кроме того, точность двойного составляет всего около 16 цифр . Все цифры за ней - мусор (в базе-10).

2 голосов
/ 25 февраля 2010

Использование %@ означает, что NSLog отправит методу description параметр и будет использовать его описание в выходных данных. Что бы ни решило NSNumber, достаточно точности для описания, это число, которое вы увидите в NSLog. Если вы сделали:

NSLog ("%.20f", [result doubleValue]);

Он должен выдавать тот же вывод, что и NSLog с intermediate.

0 голосов
/ 26 февраля 2010

NSNumbers и другие NSValues ​​- это просто обертки объектов вокруг примитивных значений. Объект будет содержать все, что вы положили в него, в зависимости от того, как вы его создали.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...