NSNumberFormatter only formats up to 14 significant digits - ios

I saw some code trying to format lat long using the following NSNumberFormatter.
NSNumberFormatter * sut = [[NSNumberFormatter alloc] init];
[sut setMaximumFractionDigits:20]; // also tried set to 15 or 16, not working too.
[sut setMaximumSignificantDigits:20];
NSLocale *enUSPOSIXLocale = [[NSLocale alloc]initWithLocaleIdentifier:#"en_US_POSIX"];
[sut setLocale:enUSPOSIXLocale];
NSString *expected = #"1.299129258067496"; // 16 significants digits
NSString *actual = [sut stringFromNumber:#(1.299129258067496)];
[[actual should] equal:expected];// Failed to pass, the actual is #"1.2991292580675"
Although in this case, we may not need to use the NSNumberFormatter to get the correct result, I'm wondering why NSNumberFormatter only returns string of up to 14 significant digits.

It only shows 14 decimal places because the double type rounds at 15 decimal places. This worked for me because you can set the number of decimal places shown.
[NSString stringWithFormat:#"%.20f", 1.299129258067496]
Just make sure the number of decimal places does not exceed the number otherwise the program makes up numbers to fill the rest. Hope this helps.

Related

NSNumberFormatter trucates leading 0's

I have written a function to convert a number from arabic numerals to digits. I have used NSNumberFormatterfor this. But the problem is the number caqn start with a zero and NSNumberFormatter truncates the leading zero. I need this value as I have to do a comparison. The number might not start with zero always. So I cannot put any other condition. Pleaes help me if anyone has a solution. Thank you.
My code is:
-(NSString*)convertNumberFromArabic:(NSString*)numberToConvert{
NSNumberFormatter *nf1 = [[NSNumberFormatter alloc] init];
NSLocale *locale = [NSLocale localeWithLocaleIdentifier:#"en"];
[nf1 setLocale:locale];
NSNumber *newNum = [nf1 numberFromString:numberToConvert];
NSString *reverseConvert = [nf1 stringFromNumber:newNum];
return reverseConvert;
}
Your question is a bit confusing. You say you want to "convert a number from arabic numerals to digits", but your method name says to Arabic. I have written the method to convert from Arabic to Latin. If you want to got the other way, you just change the YES to NO.
Here's the code:
-(NSString*)convertArabicDigitsToLatin:(NSString*)numberToConvert{
NSMutableString* result = [numberToConvert mutableCopy];
CFRange range = CFRangeMake(0, result.length);
CFStringTransform((__bridge CFMutableStringRef)result, &range, kCFStringTransformLatinArabic, YES);
return result;
}
This doesn't interpret the string as a number, it just transliterates the Arabic digits as string characters to Latin digits.

Using NSNumberFormatter to Display Extremely Large Numbers

I'm working on a calculator app for the iPhone.
I've encountered an issue using NSNumberFormatter when displaying results of calculations that are greater than 15 digits.
For example, the result of the calculation 111,111,111,111,111 x 2 = 222,222,222,222,222 (correct). However, the result of the calculation 1,111,111,111,111,111 x 2 = 2,222,222,222,220 (wrong!).
Is there a limit to how many digits that can be displayed using NSNumberFormatter, or can someone tell me why the calculation result is not displaying correctly??
Thanks in advance!
Sample code:
double absResult = fabs(_result);
NSLog(#"_result = %f", _result);
//_result is the result of the calculation that will be placed onto displayLabel below
// _result = 2,222,222,222,222,222 for the calculation 1,111,111,111,111,111 x 2
NSNumberFormatter *displayString = [[NSNumberFormatter alloc]init];
//** Adds zero before decimal point **
[displayString setMinimumIntegerDigits:1];
[displayString setUsesGroupingSeparator:YES];
[displayString setGroupingSeparator:#","];
[displayString setGroupingSize:3];
[displayString setMinimumFractionDigits:2];
[displayString setMaximumFractionDigits:2];
NSString *resultString = [displayString stringFromNumber:[NSNumber numberWithDouble: _result]];
self.displayLabel.text = resultString;
This has nothing to do with NSNumberFormatter's capabilities but only with the precision of double floating point numbers. The double type uses 8 bytes to store 53 bit of mantissa and 11 bit exponent. See the Wikipedia article.
The 53 bit mantissa is too small to exactly represent 222,222,222,222,222, so the double is set to the closest possible representation.
If you want more precision you should try NSDecimalNumber which is better suited for a calculator app anyway.

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"?

How do I get NSNumber with NSLocale smarts from a UITextField?

Getting correct localized formatting of numbers to display is easy.
But prompting for a decimal number input from a UITextField is proving tricky.
Even though the decimal keypad may present the comma for European usage instead of the stop, the method handling the input apparently still needs to be locale-savvy.
my research here on S.O. and other places suggests
-(IBAction)buttonPress:(UIButton *)sender
{
NSNumber *firstNumber = #([self.firstField.text floatValue]); // 2 alternative ways
NSNumber *secondNumber = [NSNumber numberWithFloat:[self.secondField.text floatValue]];
.
.
only gives me integers to perform arithmetic with. They aren't floats at all. They have no float value
Supposing this is the only thing the app does, and I immediately do:
.
.
NSNumberFormatter *numberFormat = [[ NSNumberFormatter alloc] init];
[ numberFormat setNumberStyle:NSNumberFormatterDecimalStyle];
[ numberFormat setLocale:[NSLocale currentLocale]];
[ numberFormat setMaximumFractionDigits:2];
NSString *displayString = [ numberFormat stringFromNumber:firstNumber];
self.resultLabel.text = displayString;
}
I am throwing the input back to a label in the ViewController without any further handling to make sure the the decimals aren't hidden by not having a formatter. No Joy. Still in integers.
Obviously the app has to do something in the way of calculation, and since one can't handle NSNumber wrappers directly, I have to resolve it before i do the conversion thing:
double xD = [firstNumber doubleValue];
double yD = [secondNumber doubleValue];
the question is, where is the decimal-ness of the input being lost?
I have no problem with the desktop keyboard and the simulator, but if i set a test device to - say - Polish then that simply won't do.
EDIT:
and here's the result from the answer provided below
// run these 4 methods first, that way you can re-use *numberFormat for the display
NSNumberFormatter *numberFormat = [[ NSNumberFormatter alloc] init];
[ numberFormat setNumberStyle:NSNumberFormatterDecimalStyle];
[ numberFormat setLocale:[NSLocale currentLocale]];
[ numberFormat setMaximumFractionDigits:2];
// here 'tis
NSNumber *firstNumber = [numberFormat numberFromString:self.firstField.text];
// do the same for other input UITextFields
// sh-boom. there you go
You need use longLongValue not longValue to convert NSString to long type. or use NSNumberFormatter->numberFromString:

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

Resources