iOS - Operations with double values [duplicate] - ios

This question already has answers here:
Objective C Issue With Rounding Float
(4 answers)
Closed 9 years ago.
The APP I'm writting must do some financial calculations, basically it's all about credits, debits and the balance. The only problem (so far) is that if I calculate 999999999.99 - 0.00 the result is 1000000000.00. Please, does anyone know why that happens? Here's my code:
NSNumber *totalCredits;
NSNumber *totalDebits;
NSNumber *balance;
self.credits = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];
totalCredits = [self.credits valueForKeyPath:#"#sum.amount"];
double totalCreditsDouble = [totalCredits doubleValue];
self.creditLabel.text = [NSString stringWithFormat:#"%1.2f", totalCreditsDouble];
self.debits = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];
totalDebits = [self.debits valueForKeyPath:#"#sum.amount"];
double totalDebitsDouble = [totalDebits doubleValue];
self.debitLabel.text = [NSString stringWithFormat:#"%1.2f", totalDebitsDouble];
balance = [NSNumber numberWithFloat:([totalCredits floatValue] - [totalDebits floatValue])];
double balanceDouble = [balance doubleValue];
self.balanceLabel.text = [NSString stringWithFormat:#"%1.2f", balanceDouble];
All the data is stored as Double.

The C type double is generally not very well suited for financial calculations.
Foundation.framework has a good data type for that: NSDecimalNumber. NSDecimalNumber uses a decimal representation and has 36 digits of precision.

http://floating-point-gui.de/ is a good resource to start with. You are trying to store exact values using a datatype which cannot represent them with the accuracy or precision you need.
if the integrity of these calculations is important to you then you need to switch to storing these values in a format which accurately represents them.
In this case a simple solution might be to store all of your currencies in their smallest possible denomination (e.g. cents) as integers (assuming you don't need fractional cents and handle any division carefully and consistently).

Related

Convert NSString with factor (e.g. #"3/4") to NSNumber [duplicate]

This question already has answers here:
Convert to Float and Calculate
(3 answers)
What is a fast C or Objective-C math parser? [closed]
(4 answers)
Closed 9 years ago.
I want to convert a string for example
NSString *stringWithNumber = #"3/4"
into a NSNumber.
How is this possible?
You can use an NSEXpression to "calculate" the value. Note that you will have the regular int division problem with "3/4".
NSExpression *expression = [NSExpression expressionWithFormat:#"3.0/4.0"];
NSNumber *result = [expression expressionValueWithObject:nil context:nil];
If you are only working with n/m fractions, and you mean to have a number representing the result of the fraction, you can do something like
NSString *fraction = #"3/4";
NSArray *components = [fraction componentsSeparatedByString:#"/"];
float numerator = [components[0] floatValue];
float denominator = [components[1] floatValue];
NSNumber *result = #(numerator/denominator);
NSLog(#"%#", result); // => 0.75
Of course this can easily break in case of malformed strings, so you may want to check the format before performing the above computation.
NOTE
In case the fractions coming in input have a format compatible with native float division, David's answer is definitely sleeker and less clunky than mine. Although if you have an input like #"3/4", it won't work as expected and you definitely need to do something like I suggested above.
Bottom line, you should specify better your requirements.

Objective C: NSNumber from Array to float [duplicate]

This question already has an answer here:
How to convert NSNumber objects for computational purposes?
(1 answer)
Closed 9 years ago.
I have an array:
SomeArray =[[NSMutableArray alloc]initWithObjects:[NSNumber numberWithFloat:50.0],[NSNumber numberWithFloat:120.0],[NSNumber numberWithFloat:200.0],nil];
When I retrieve it:
NSNumber* Target = [SomeArray objectAtIndex:0];
When I NSLog it:
NSLog(#"Target %d",Target);
it return something funky like
2013-06-26 01:47:58.940 KKK[1027:c07] Target 121016880
What is the proper way to do this?? I just need the number in the array to be used as float.
You are retrieving a NSNumber, which is an object.
%d is for logging decimals, which is not your case.
Either you log it with
NSLog(#"Target %#", target);
or you convert it to a float and use %f
NSLog(#"Target %f", [target floatValue]);
And PLEASE don't use capitalized identifiers for variables!
You are asking for a decimal %d in the log and also a primitive type. NSNumber is an object that wraps a primitive type numbers. So you can do like that
NSLog(#"target %f",[Target floatValue]) or NSLog(#"target %#",Target). With the first you are sending a message to the object to unwrap the float value with the latter you are asking for the object description that in this case is the number

Store decimal number [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 9 years ago.
I need to store a decimal number and neither a string, int or number seem to do what i want. I cannot use NSNumber because I need to be able to change it later.
I searched the whole internet but I doesn't seem to be able to find it.
The answer is probably pretty simple.
Thanks!
UPDATE:
some kind of data here
looping code{
nslog(save number);
save number 3.1415926535;
delete all data that has been stored
//now string doesn't exist anymore
}
I need to be able to save that number outside the loop in "some kind of data here" because when the loop starts over everything that is created from the loop is deleted.
Try using NSNumber like so:
double myValue = 20.0;
NSNumber* number = [NSNumber numberWithDouble:myValue];
// Do something with NSNumber like write it to disk, put it in an array, dictionary whatever ....
// Then pull it back out
double myOldValue = [number doubleValue];
To pull a double value out after the app has been closed (I'm interpreting that to mean "backgrounded" or "suspended"), try writing it to NSUserDefaults before the app is backgrounded and then pull it back out when your app resumes.
// Write a double to NSUserDefaults
[[NSUserDefaults standardUserDefaults] setDouble:myValue forKey:#"myDoubleValue"];
// Write an NSNumber to NSUserDefaults
[[NSUserDefaults standardUserDefaults] setObject:number forKey:#"myNumberWithDoubleValue"];
// Extract double from NSUserDefaults
double myReallyOldDoubleValue = [[NSUserDefaults standardUserDefaults] doubleForKey:#"myDoubleValue"];
// Extract NSNumber from NSUserDefaults
NSNumber* myReallyOldNumberValue = [[NSUserDefaults standardUserDefaults] objectForKey:#"myNumberWithDoubleValue"];
Or in your psuedo code:
NSNumber *someValue = [NSNumber numberWithDouble:0.0];
some kind of data here
looping code {
nslog(save number)
someValue = [NSNumber numberWithDouble:3.1412];
delete all data that has been stored
}
Store a pointer to your number or a instance variable or class property
You can use NSNumber, or is decimal subclass NSDecimalNumber. Just because the objects themselves are immutable doesn't mean you can't change the value a given variable points to. For example:
NSDecimalNumber *a = [NSDecimalNumber numberWithInt:2];
a = [a decimalNumberByAdding:[NSDecimalNumber numberWithInt:12]];
a = [a decimalNumberByDividing:[NSDecimalNumber numberWithDouble:2.3]];
This is just like real ints, which are also immutable.
double a = 2;
a = a + 12;
a = a / 2.3;
That being said, NSDecimalNumber is quite verbose. If you can get away with a primitive type (say, doing computations in cents instead of dollars) that might be preferable.
Just use a double. When it comes time to store it, you can get a number like this:
NSNumber *number = #(myDouble);
To change an NSNumber into a double,
double myDouble = [number doubleValue];

ios: NSLog show decimal value

NSNumber *weekNum = [dictionary valueForKey:#"inSeasonFor"];
NSDecimalNumber *newWeekNum = ([weekNum intValue] *2)/4;
NSLog(#"%", [newWeekNum decimalValue]);
How can I divide weekNum*2 by 4 and keep the decimal value and print it?
You mean you want the fractional part as well, right?
NSNumber *weekNum = [dictionary valueForKey:#"inSeasonFor"];
// multiplication by 2 followed by division by 4 is division by 2
NSLog(#"%f", [weekNum intValue] / 2.0f);
//we can also use intfloat to resolve.

NSNumber storing float. Please NO scientific notation?

My code looks like this
NSNumber *inputToNumber = [NSNumber numberWithFloat:[textField.text floatValue]];
the value from the textfield is actually a telephone number. It's stored in NSNumber as an annoying (2.0)78966e+08
How can I just get NSNumber to store it as 0207896608?
I think that the basic idea to store a phone number into a NSNumber is flawed:
how do you discriminate between numbers with or without leading 0 ?
how do you store phone numbers from foreign countries ?
I would use NSString in place of NSNumber.
Just because it's called a number doesn't mean a "telephone number" is a number in the same sense that "5" or "pi" are.
Either you should treat a telephone number as a string, or you should create a TelephoneNumber model class to represent each one.
Consider that there are places in the world where numbers don't have leading 0's and where a number with a leading 0 is not the same as the same number without a leading 0.
05843924 != 5843924
So stop being lazy with that NSNumber hacks and build your own phone-number class.
Scientific notation is used in may computer languages as the default output of very large (or very small) numbers. If you want the number to be output as a decimal, you need to specify the output format (the implementation varies by language.)
Also, julesjacobs is correct. You should not use FLOAT for a phone number as it is subject to binary rounding errors. Using INT or STRING will save you lots of headaches.
If you need to be able to deal with it as numbers maybe you should break it up into its parts, and store each part as an integer.
01112223333
country code 0
area code 111
prefix 222
number 3333
Or you could store the whole thing as a string if you don't need to manipulate it.
Are you storing a phone number in a float? You should consider using an integer or string. Perhaps:
NSNumber *inputToNumber = [NSNumber numberWithInt:[textField.text intValue]];
Hey Guys what do you think of this, It seems to full-fill my purposes. Only UK at the moment so will worry about localization when I get a chance.
I use this to get to store the number
NSNumber *inputToNumber = [NSNumber numberWithLongLong:(long long)[[textField.text stringByReplacingOccurrencesOfString:#" " withString:#""] longLongValue]];
And this method formats my telephone number and takes care of the preceeding 0 mentioned.
-(NSString *)phoneNumberString:(NSNumber *)phoneNumber {
//Add a zero because NSNumber won't save a preceeding zero
NSString *telephoneString = [[NSString alloc] initWithFormat:#"0%#", [phoneNumber stringValue]];
if (telephoneString.length >= 4) {
NSString *firstPart = [[NSString alloc] initWithString: [telephoneString substringToIndex:4]];
NSString *secondPart = [[NSString alloc] initWithString: [telephoneString substringFromIndex:4]];
//Add the two parts together with a space inbetween
NSString *formattedTelephoneString = [NSString stringWithFormat:#"%# %#", firstPart, secondPart];
//send it back to the cellForRow TableCell Method
[firstPart release];
[secondPart release];
[telephoneString release];
return formattedTelephoneString;
}
else {
return telephoneString;
}
}
Thanks for all the comments. I'm gonna mark the answer as whoever suggested NSString as I fear I will revert to using NSString for this instead of my above workaround.

Resources