Цель C Математическая Формула Fail - PullRequest
2 голосов
/ 07 августа 2010

noob здесь хочет вычислить сложный процент на iPhone.

float principal;
float rate;
int compoundPerYear;
int years;
float amount;

формула должна быть: сумма = основная * (1 + ставка / соединениеPerYear) ^ (ставка * годы)

Iполучить немного неправильный ответ:

amount = principal*pow((1+(rate/compoundPerYear)), (compoundPerYear*years));

Я тестирую его со скоростью .1, но отладчик сообщает .100000001.

Я делаю это неправильно?Должен ли я использовать double или специальный класс (например, NSNumber)?

Спасибо за любые другие идеи!


После дальнейших исследований кажется, что класс NSDecimalNumber может быть именно тем, что мне нужно.Теперь мне просто нужно выяснить, как использовать этого плохого мальчика.

Ответы [ 2 ]

6 голосов
/ 07 августа 2010

double приблизит вас, но вы не можете точно представить 1/10 в двоичном виде (в любом случае, используя запись IEEE с плавающей запятой).

Если вам действительно интересно, вы можете посмотреть Что должен знать каждый учёный-компьютерщик об арифметике с плавающей точкой . Ссылка постыдно похищена из другого ТА потока.

Быстрое и грязное объяснение состоит в том, что с плавающей точкой хранится в двоичном виде с битами, которые представляют дробные степени 2 (1/2, 1/4, 1/8, ...). Просто нет математического способа сложить эти дроби точно в 1/10, поэтому 0,1 не может быть точно представлено в нотации IEEE с плавающей запятой.

double увеличивает точность числа, предоставляя вам больше цифр до / после радиуса, но это не меняет формат двоичного файла таким образом, чтобы это можно было компенсировать. Скорее всего, вы получите дополнительный бит где-то чуть позже.

Смотри также:

и другие подобные темы.


Дальнейшее расширение, которое я размышлял по дороге домой с работы: один из способов, которым вы могли бы справиться с этим, - просто представить все денежные значения в центах (в виде целых чисел), а затем преобразовать в формат dollar.cents при отображении данные. На самом деле это тоже довольно просто, так как вы можете воспользоваться усечением целочисленного деления при конвертации:

int interest, dollars, cents;
interest = 16034; //$160.34, in cents
dollars = value / 100; //The 34 gets truncated: dollars == 160
cents = value % 100; //cents == 34
printf("Interest earned to date: $%d.%d\n", dollars, cents);

Я не знаю Objective-C, но, надеюсь, этот пример на C тоже имеет смысл. Опять же, это всего лишь один из способов справиться с этим. Это также было бы улучшено благодаря наличию функции, которая выполняет форматирование строки всякий раз, когда вам нужно показать данные.

Очевидно, что вы можете придумать свой (даже лучше!) Способ сделать это, но, возможно, это поможет вам начать. Если у кого-то еще есть предложения по этому вопросу, я бы тоже хотел их услышать!

2 голосов
/ 07 августа 2010

Краткий ответ: Никогда не используйте числа с плавающей запятой для денег.

Самый простой способ работы с большинством платформ состоит в том, чтобы представлять деньги в виде целых чисел их наименьшей единицы. Наименьшая единица измерения часто равна центу, хотя часто базовые единицы составляют 1/10 или 1/100 процента.

На многих платформах также доступны типы чисел, которые могут представлять десятичные числа с фиксированной запятой.

Обязательно сделайте правильное округление. Финансовая бухгалтерия часто использует банковское округление.

...