views:

131

answers:

2

Hi, noob here wants to calculate compound interest on iPhone.

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

formula should be: amount = principal*(1+rate/compoundPerYear)^(rate*years)

I get slightly incorrect answer with:

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

I'm testing it with rate of .1, but debugger reports .100000001 .

Am I doing it wrong? Should I use doubles or special class (e.g., NSNumber)?

Thanks for any other ideas!


After further research it seems that the NSDecimalNumber class may be just what I need. Now I just have to figure out how to use this bad boy.

+5  A: 

double will get you closer, but you can't represent 1/10 exactly in binary (using IEEE floating point notation, anyway).

If you're really interested, you can look at What Every Computer Scientist Should Know About Floating-Point Arithmetic. Link shamefully stolen from another SO thread.

The quick and dirty explanation is that floating point is stored in binary with bits that represents fractional powers of 2 (1/2, 1/4, 1/8, ...). There is simply no mathematical way to add up these fractions to exactly 1/10, thus 0.1 is not able to be exactly represented in IEEE floating point notation.

double extends the accuracy of the number by giving you more numerals before/after the radix, but it does not change the format of the binary in a way that can compensate for this. You'll just get the extra bit somewhere later down the line, most likely.

See also:

and other similar threads.


Further expansion that I mulled over on the drive home from work: one way you could conceivably handle this is by just representing all of the monetary values in cents (as an int), then converting to a dollars.cents format when displaying the data. This is actually pretty easy, too, since you can take advantage of integer division's truncating when you convert:

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

I don't know Objective-C, but hopefully this C example makes sense, too. Again, this is just one way to handle it. It would also be improved by having a function that does the string formatting whenever you need to show the data.

You can obviously come up with your own (even better!) way to do it, but maybe this will help get you started. If anyone else has suggestions on this one, I'd like to hear them, too!

eldarerathis
Thanks for your reply. I hope I can get the time (and the brains) to read that What Every Computer. . . article one of these days, but the very beginning of it was helpful.The cents only scheme you suggest is ingenious, but too confusing for me. Would it work with percentages, multiplication, exponents, logorthms, etc.?
alrightSpider
It can work, yes. The main advantage is that you have one less floating point number to worry about. Even if you use NSDecimalNumber to represent the rate, it might end up being easier to just leave the monetary values as cents. Then you can perform integer arithmetic whenever possible (such as adding two amounts of money together). If NSDecimalNumber is precise enough for your calculations, then it makes perfect sense to just go with that, though. Again, I'm not much of an objective-C guy :)
eldarerathis
IMHO, accounting and floating point mix only with immense care and consideration. My understanding is that there are established best practices, and it would be a good idea to learn about them and follow them. A good first step is to start with working in cents rather than dollars. If you still need a floating point value type, then switching to one that works in base 10 instead of base 2 can help. This is only the very tip of a *very large* iceberg of issues.
RBerteig
A: 

Short answer: Never use floating point numbers for money.

The easy way that works across most platforms is to represent money as integer amounts of its smallest unit. The smallest unit is often something like a cent, although often 1/10 or 1/100 of a cent are the real base units.

On many platforms, there are also number types available that can represent fixed-point decimals.

Be sure to get the rounding right. Financial bookkeeping often uses banker's rounding.

Svante