Examples of doing decimal math in iPhone - iphone

I'm pulling decimal values from a sql table as a text field which i then convert to an NSDecimalNumber (this is simply because i didnt know read/write decimal values to sqllite).
Anyway, now i've hit a wall now that im trying to do simple math routines on these decimal variables. Such as, Sum = Balance * Interest_Rate. The idea is that im working with money calculations.
Do you know of samples/tutorials that teaches how to do these operations using either NSDecimal, NSDecimalNumber, or both?
Thanks.

To init:
NSString *number = #"123.4";
NSDecimalNumber *myDecimal = [[NSDecimalNumber alloc] initWithString: number];
To do what you want to do:
NSDecimalNumber *sum = [[NSDecimalNumber alloc] initWithDecimal:[balance decimalNumberByMultiplyingBy: interest_rate];
How?
Well you make a NSDecimalNumber and alloc and then initWithDecimal. What decimal? balance multiplied (decimalNumberByMultiplyingBy) by interest_rate.

Related

Conversation from NSCFString to NSNumber

I've below numbers which are stored as NSCFString into SQLite
These numbers converts perfectly
475602307163925662
1529228456639250520
I am converting these like, (NSNumber *) [myDictionary valueForKey:#"stringData"]; and its working perfectly
These numbers couldn't converts perfectly
14154269406789154303
13207084142614401684
12870871772958895646
I want to convert these NSCFString into NSNumber. I try using below code and google it but dont get exact solution as I want. Any help would be appriciated.
NSNumberFormatter *f=[[NSNumberFormatter alloc] init];
[f setNumberStyle:NSNumberFormatterDecimalStyle];
NSNumber *myNumber=[f numberFromString:[myDictionary valueForKey:#"stringData"]];
[f release];
but it converts my number something like 9.45214212452152
I tried some other way as well but its also not working well.
NSNumber *myNumber=[NSNumber numberWithLong:[myDictionary valueForKey:#"stringData"]];
Casting an object as another object (aka (NSNumber *)) does not "convert" it. It just promises the compiler that you're working with an object of that class which you aren't.
The reason why some numbers are totally failing is because they're too large to fit in the standard int/float/long sizes. Instead of NSNumber, use NSDecimalNumber - a subclass of NSNumber (so you can still use all of the NSNumber methods as well). It's specifically designed to handle large numbers:
NSDecimalNumber *number = [NSDecimalNumber decimalNumberWithString:<your string object>];

Formatting number with NSNumberFormatter that already has decimals and thousand seperators

I have these number formats:
100000,459
100000459
100.000
100.000,59
100.000.000,39
The number changes as the user input values to it. And for every value added, I need to re-format the number with NSNumberFormatter. The problem is that this number already has . and , and the formatter does not seem to handle these correctly. It comes out like this:
100 000,00
100 000 459,00
100,00
100,00
100,00
E.g. I want 100000,459 to become 100 000,459.
The code I use now:
NSNumber *amount = [NSNumber numberWithInt:[string intValue]];
NSNumberFormatter *currencyFormatter = [[[NSNumberFormatter alloc] init] autorelease];
[currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:#"nb_NO"];
[currencyFormatter setLocale:locale];
NSString *commaString = [currencyFormatter stringForObjectValue:amount];
How can I format already formatted numbers?
In the last line you are trying to format a string rather than a number. Try this:
NSString *commaString = [currencyFormatter stringFromNumber:amount];
Here is a good reference.
I've looked at that specific reference. It differs from my problem because in my case I may already have decimals when formatting.
NSNumberFormatter formats a number to a string representation and it needs the correct representation of the number to be able to format it as expected. By the look of your code sample you are providing the formatter with an integer value and that is why you are getting the output you are getting. With string = #"100000,459" [string intValue] gives you 100000. Which is why the output from the formatter is 100 000,00.
What you need to do is to first get the string into a double representation. That can be achieved by using NSScanner. You just have to make sure that you scan the numbers in the correct locale so the thousand separators are detected properly. Your first string can be converted to a double by:
NSScanner *scanner = [NSScanner scannerWithString:#"100000,459"];
[scanner setLocale:locale];
double val;
[scanner scanDouble:&val];
NSNumber *amount = [NSNumber numberWithDouble:val];
How to properly handle the thousand separators I don't know.

How to convert string with number to NSDecimalNumber that has a comma not a decimal point?

I have an interface giving me numbers like this 0000000012345,78
So i figured out how to make a number out of them. But I need to calculate with that number and what I actually need is a decimal number.
NSNumberFormatter *fmtn = [[NSNumberFormatter alloc] init];
[fmtn setFormatterBehavior:NSNumberFormatterBehavior10_4];
[fmtn setNumberStyle:NSNumberFormatterDecimalStyle];
[fmtn setDecimalSeparator:#","];
NSNumber *test = [fmtn numberFromString:#"0000000012345,78"];
How can I make my NSNumber to a NSDecimalNumber?
EDIT: This is the code I ended up with:
NSDictionary *localeDict = [NSDictionary dictionaryWithObject:#"," forKey:#"NSDecimalSeparator"];
NSDecimalNumber *test = [[NSDecimalNumber alloc] initWithString:#"00000000012345,78" locale:localeDict];
How to put together the locale dictionary could not be described as "well documented" and it took me some googling to find an example.
This one also worked:
NSLocale *deLoc = [[NSLocale alloc] initWithLocaleIdentifier:#"de"];
NSDecimalNumber *testd = [NSDecimalNumber decimalNumberWithString:#"00000000012345,78" locale:deLoc];
To convert an NSNumber to NSDecimalNumber, wouldn't it make more sense to avoid the character representation altogether with this code?
NSNumber* source = ...;
NSDecimalNumber* result = [NSDecimalNumber decimalNumberWithDecimal:[source decimalValue]];
If you check out the NSDecimal Class Reference, you'll see you can create new NSDecimalNumbers from NSStrings (with and without a locale), actual numbers, etc.
If you wanted to convert an NSNumber to an NSDecimalNumber, you could do something like this:
NSDictionary *locale = ...;
NSNumber *number = ...;
NSDecimalNumber *decimalNumber = [NSDecimalNumber decimalNumberWithString:[number descriptionWithLocale:locale] locale:locale];
Of course, you'll have to correctly create the locale, and such, but that's an exercise left up to you (it might be handy to check out the NSNumber Class Reference, the NSLocale Class Reference, and the Locales Programming Guide).
[NSDecimalNumber decimalNumberWithString:#"0000000012345,78"];
Use caution about the locale, though; if you run that code on an iPhone whose region format is not set to French, it might not return what you expect. So you might want to use:
+ (NSDecimalNumber *)decimalNumberWithString:(NSString *)numericString locale:(NSDictionary *)locale
instead.

Problem to destroy or tweet (inReplyTo) with the MGTwitterEngine- Can´t pass the right NSNumber to the methods

I hope I don´t annoy you and you don´t have to answer this, but
here is a little bit more explanation of my problem. I got all of the ids of the tweets with a NSArray. Then I set a NSNumber with:
NSNumber =[NSArray objectAtIndex:indexPath.row];
to get the right id of the tweet in the TableView row. Now I just wrote this:
unsigned long fooo = NSNumber;
NSLog("%#", fooo) // The right number
[twitterEngine deleteUpdate:fooo];
But the finalURL has a other number. So for example fooo is: 8043688359, the finalUrl is this:
finalURL = https://twitter.com/statuses/destroy/62024352.xml
Also I get the HTTP error 403
All other methods like sendUpdate, getTimeline etc. are working.
Just the deleteUpdate and the sendUpdate: inReplyTo aren´t
working. I think it has something with a wrong number to do.
Sorry for my bad English, bad I´m a young student from Germany
and I´m just learning Objective-C (or programming generally) for
three weeks.
The original methodes looking like that:
- (NSString *)sendUpdate:(NSString *)status inReplyTo:(unsigned long)updateID; // statuses/update
- (NSString *)deleteUpdate:(unsigned long)updateID; // statuses/destroy
Thanks!
Got the answer: The MGTwitterEngine wants a unsigned long, but the iPhone is 32bit and so the the 64bit number gets smaller and MGTwitterEngine gets the wrong number.
You have to edit the MGTwitterEngine. Just write unsigned long long in the methods.
NSNumber is a class not an instance. The code could look something like the following:
NSNumber *myNumber = [NSArray objectAtIndex:indexPath.row];
unsigned long fooo = [NSNumber longValue];
NSLog("%l", fooo); // The right number
[twitterEngine deleteUpdate:fooo];
The return from -objectAtIndex: is an object and long is a primitive value. So you need to get the primitive long value out of the NSNumber object.
BTW, the odd number you are getting back is the memory address for the instance of the NSNumber.
Aproach it differently, as far as I can tell your code is something like:
NSNumber *aNumber = [anArray objectAtIndex:index.row];
unsigned long = aNumber;
In stead of using a unsigned long you should use a NSUinteger btw.
and doing it more directly:
NSUInteger anInteger = [[anArray objectAtIndex:index.row] longValue]; // or longLongValue];
done.
Tell me if I mis understood you.

How to create an NSMutableArray of floating point values

I'm new to Objective-C and iPhone development, and I'm trying to store floating-point values in an NSMutableArray, but when I do I get an error saying "incompatible type for argument 1 of 'addObject". What am I doing wrong? I'm trying to create an array of doubles that I can perform math calculations with.
NSMutableArray only holds objects, so you want an array to be loaded with NSNumber objects.
Create each NSNumber to hold your double then add it to your array. Perhaps something like this.
NSMutableArray *array = [[NSMutableArray alloc] init];
NSNumber *num = [NSNumber numberWithFloat:10.0f];
[array addObject:num];
Repeat as needed.
Use an NSNumber to wrap your float, because the dictionary needs an object:
[myDictionary setObject:[NSNumber numberWithFloat:0.2f] forKey:#"theFloat"];
/* or */
[myDictionary setObject:#0.2f forKey:#"theFloat"];
retrieve it by sending floatValue:
float theFloat = [[myDictionary objectForKey:#"theFloat"] floatValue];
Code is untested.
You can wrap many other data types in NSNumber too, check the documentation. There's also NSValue for some structures like NSPoint and NSRect.
In Cocoa, the NSMutableDictionary (and all the collections, really) require objects as values, so you can't simply pass any other data type. As both sjmulder and Ryan suggested, you can wrap your scalar values in instances of NSNumber (for number) and NSValue for other objects.
If you're representing a decimal number, for something like a price, I would suggest also looking at and using NSDecimalNumber. You can then avoid floating point inaccuracy issues, and you can generally use and store the "value" as an NSDecimalNumber instead of representing it with a primitive in code.
For example:
// somewhere
NSDecimalNumber* price = [[NSDecimalNumber decimalNumberWithString:#"3.50"] retain];
NSMutableArray* prices= [[NSMutableArray array] retain];
// ...
[prices addObject:price];
NSMutableArray *muArray = [[NSMutableArray alloc] init];
NSNumber *float = [NSNumber numberWithFloat:210.0f];
NSNumber *float1 = [NSNumber numberWithFloat:211.0f];
[muArray addObject:float];
[muArray addObject:float1];
NSlog(#"my array is--%#",muArray);