Convert long NSString to NSNumber - ios

I am unable to reliably convert longer NSString to NSNumber. Specifically, I am converting MPMediaEntityPropertyPersistentID as a string to a NSNumber Sometimes it works, usually it doesn't.
Conversion code:
NSString *keke = [jsonArray objectForKey:#"next"];
NSNumberFormatter * f = [[NSNumberFormatter alloc] init];
[f setNumberStyle:NSNumberFormatterDecimalStyle];
NSNumber *persistentIDasNumber = [f numberFromString:keke];
Here is an example of a successful string to number conversion:
String: 3813955856659208324
Number: 3813955856659208324
And here is an unsuccessful conversion:
String: 12790162104953153719
Number:1.279016210495315e+19
It's close but what is happening at the end? Is it too large?

Apparently the largest integer number that can be processed with NSNumberFormatter is long long, which is 9223372036854775807. Anything beyond that will lose precision and not come out as you put it in.
Instead use NSDecimalNumber, a concrete subclass of NSNumber. And it can even parse strings itself:
NSDecimalNumber *dn=[[NSDecimalNumber alloc]initWithString:#"12790162104953153719"];
NSLog(#"dn: %#",dn);
NSDecimalNumber can handle up to 38 digit long decimal numbers before it loses precision.

This is how you do it:
unsigned long long number = [[jsonArray objectForKey:#"next"] longLongValue];
NSNumber * numberValue = [NSNumber numberWithUnsignedLongLong:number];

Related

How to avoid rounding off the float value when called from sqlite

I am using the following statement to get a float value from table:
NSNumber *f = [NSNumber numberWithDouble:(double)sqlite3_column_double(statement, 0)];
The value in the database is 23.679999999 but I am getting 23.68. I tried numberWithFloat but i got the same result.
Can anyone tell me how to get the value without rounding off?
NSNumber-wrapped-double is not a suitable data type for storing decimal values when all digits must be preserved exactly. Use NSDecimalNumber instead:
unsigned char *c = sqlite3_column_text(statement, 0);
NSNumber *f = nil;
if (c) {
NSString *numStr = [NSString stringWithUTF8String:c];
f = [NSDecimalNumber decimalNumberWithString:numStr];
}
This should preserve all significant digits available in your text representation, as long as you use the native value. Converting to float or double may result in rounding due to differences in representation.

NSNumberFormatter numberFromString decimal number

I'm trying to parse a NSString with a NSNumberFormatter like following.
NSNumberFormatter *myFormatter = [[[NSNumberFormatter alloc] init];
NSNumber *myNumber = [myFormatter numberFromString:#"42.00000"];
numberFromString returns a NSNumber object in the simulator but not on a device.
The decimals (.00000) are causing the return value to be nil on a device because parsing 42 (without the decimals) works just fine (both in the simulator and on a device).
The reason I'm using a NSNumberFormatter is because is like how it returns nil if the string is not a valid number (which is working against me here :p). NSString doubleValue does not provide this kind of behaviour. Also, NSDecimalNumber decimalNumberWithString doesn't do the job because [NSDecimalNumber decimalNumberWithString:#"4a2.00000"] returns 4.
Any ideas why this would not work on a device?
Is it the locale? I tried setting myFormatter.numberStyle = NSNumberFormatterNoStyle and NSNumberFormatterDecimalStyle but it changes nothing.
As #rmaddy already said in a comment, the decimal separator of NSNumberFormatter is
locale dependent. If you have a fixed input format with the dot as decimal separator,
you can set the "POSIX locale":
NSNumberFormatter *myFormatter = [[NSNumberFormatter alloc] init];
[myFormatter setLocale:[NSLocale localeWithLocaleIdentifier:#"en_US_POSIX"]];
NSNumber *myNumber = [myFormatter numberFromString:#"42.00000"];
Alternatively, you can use NSScanner to parse a double value, as e.g. described
here: parsing NSString to Double
42.00000 is not a string mate, why not #"42.00000"?

Converting double to string return strange value in objective c

I have an NSDictionary which consist of multiple key/pair values. One of them consist double value.
NSNumber *goalValue = [info objectForKey:#"goalValue"];
I put breakpoint and I found that goalValue store the normal value that I need.
and just below I convert it to NSSting like
NSString *stringValue=[goalValue stringValue];
and this stringValue store very strange value.
Guys please help me. I am totally puzzled, I did goggle but nothing change. Please help me. Thanks in advance.
The method stringValue will convert the NSNumber to string by internally calling descriptionWithLocale: with locale as nil and this method in turn will call initWithFormat:locale:,
From Apple docs,
To obtain the string representation, this method invokes NSString’s initWithFormat:locale: method, supplying the format based on the type the NSNumber object was created with:
So format specifier used for double is %0.16g(i.e. 16 digit precision) hence the value 98.09999999999999
I'd suggest using NSNumberFormatter,
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
[numberFormatter setMaximumFractionDigits:2]; //2 decimal places, change this as required.
NSString *string = [numberFormatter stringFromNumber:goalValue];
Hope that helps!
To prevent this behavior, I suggest using NSDecimalNumber (also this is from my experience best format when dealing with very precise amounts)
NSDecimalNumber *doubleDecimal = [[NSDecimalNumber alloc] initWithDouble:[info objectForKey:#"goalValue"]];
for two digits formatting, use numberFormatter
NSNumberFormatter * nf = [[NSNumberFormatter alloc] init];
[nf setMinimumFractionDigits:2];
[nf setMaximumFractionDigits:2];
NSString *stringValue = [nf stringFromNumber:doubleDecimal]
Its showing the rounded value so you can round the value to single digit using NSNumberFormatter.
NSNumberFormatter *fomatter = [[NSNumberFormatter alloc] init];
[fomatter setMaximumSignificantDigits:2];
NSString *stringValue=[fomatter stringFromNumber:goalValue];

NSNumber to float Value

When I convert NSNumber to float value using 'floatValue', there is a difference in precision. Example, I have a NSNumber 'myNumber' having value 2.3, and if I convert myNumber to float using 'floatValue', its value becomes, 2.29999. But I need exactly 2.30000. There is no problem with number of zeros after 2.3, I need '2.3' instead of '2.9'.
How can I do so?
I had similar situation where I was reading value and assigning it back to float variable again.
My Problem statement:
NSString *value = #"553637.90";
NSNumber *num = #([value floatValue]); // 1. This is the problem. num is set to 553637.875000
NSNumberFormatter *decimalStyleFormatter = [[NSNumberFormatter alloc] init];
[decimalStyleFormatter setMaximumFractionDigits:2];
NSString *resultString = [decimalStyleFormatter stringFromNumber:num]; // 2. string is assigned with rounded value like 553637.88
float originalValue = [resultString floatValue]; // 3. Hence, originalValue turns out to be 553637.88 which wrong.
Following worked for me after changing lines:
NSNumber *num = #([value doubleValue]); // 4. doubleValue preserves value 553637.9
double originalvalue = [resultString doubleValue]; // 5. While reading back, assign to variable of type double, in this case 'originalValue'
I hope this would be helpful. :)
If you need exact precision, don't use float. Use a double if you need better precision. That still won't be exact. You could multiply myNumber by 10, convert to an unsigned int and perform your arithmetic on it, convert back to a float or double and divide by 10 and the end result might be more precise. If none of these are sufficiently precise, you might want to look into an arbitrary precision arithmetic library such as GNU MP Bignum.
I've done the following but it is showing me correctly
NSNumber *num = [NSNumber numberWithFloat:2.3];
float f = [num floatValue];
NSLog(#"%f", f);
You can play with something like this:
float x = 2.3f;
NSNumber *n = [NSNumber numberWithFloat:x];
NSNumberFormatter *fmt = [[NSNumberFormatter alloc] init];
[fmt setPositiveFormat:#"0.#"];
NSString *s = [fmt stringFromNumber:n];
float f = [s floatValue];

Convert NSString to currency format

In Java we do this statement to have a $ currency format.
double num1 = 3.99 ;
double num2 = 1.00 ;
double total = num1 + num2;
System.out.printf ("Total: $ %.2f", total);
The result is:
Total: $4.99
//--------------------------------
Now in iOS how can I get same format if I have the following statement :
total.text = [NSString stringWithFormat:#"$ %d",([self.coursePriceLabel.text intValue])+([self.courseEPPLabel.text intValue])+10];
Note:
If I use doubleValue the output always is 0 .
You can do the same thing with NSString:
NSString *someString = [NSString stringWithFormat:#"$%.2lf", total];
Note that the format specifier is "%lf" rather than just "%f".
But that only works for US dollars. If you want to make your code more localizable, the right thing to do is to use a number formatter:
NSNumber *someNumber = [NSNumber numberWithDouble:total];
NSNumberFormatter *nf = [[NSNumberFormatter alloc] init];
[nf setNumberStyle:NSNumberFormatterCurrencyStyle];
NSString *someString = [nf stringFromNumber:someNumber];
Of course, it won't do to display a value calculated in US dollars with a Euro symbol or something like that, so you'll either want to do all your calculations in the user's currency, or else convert to the user's currency before displaying. You may find NSValueTransformer helpful for that.

Resources