NSNumberFormatter iOS big double value - objective-c

I have a problem formatting big numbers.
I first format a string to a number and since i need to save a string, i get the stringValue from it:
formatter = [[NSNumberFormatter alloc] init];
[formatter setLocale:[NSLocale currentLocale]];
[formatter setNumberStyle:NSNumberFormatterDecimalStyle];
[formatter setUsesSignificantDigits:NO];
[formatter setMaximumFractionDigits:6];
[formatter setMinimumFractionDigits:0];
[formatter setGroupingSeparator:#""];
value = [formatter numberFromString:textField.text];
label = [value stringValue]
and everything is ok, i.e. if i enter 123456745678592.6, i'll get 123456745678592.6.
Then i've to format the string because of different locale:
numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setLocale:[NSLocale currentLocale]];
[numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
[numberFormatter setGroupingSeparator:#""];
[numberFormatter setUsesSignificantDigits:NO];
[numberFormatter setMinimumFractionDigits:0];
[numberFormatter setMaximumFractionDigits:6];
tempString = myNumberString;
NSLog(#"number: %#",[NSNumber numberWithDouble:[tempString doubleValue]]);
tempString = [numberFormatter stringFromNumber:[NSNumber numberWithDouble:[tempString doubleValue]]];
NSLog(#"string translated: %#",tempString);
and i get this:
"number: 123456745678592.6"
"string translated: 123456745678593"
This rounding happens when the significative digits are greater than 15.
Let's say i enter:
12345674567859.2
i then get the right number, i.e.
"number: 12345674567859.2"
"string translated: 12345674567859.2"
with:
12345674567859.23
i get:
"number: 12345674567859.23"
"string translated: 12345674567859.2"
but with:
1234567456785921
i get this:
"number: 1234567456785921"
"string translated: 1234567456785920"
Is this an intrinsic limit of the nsnumberformatter, because the documentation says nothing about this, or i'm doing something wrong?

Could you check what is the actual class of the number? Is it NSNumber or NSDecimalNumber?
A NSNumber is backed up by a double and cannot hold more than 15 significant decimal digits. On the other hand, NSDecimalNumber uses decimal arithmetics and can hold up to 32 significant digits.
I have already learned that NSDecimalFormatter cannot format NSDecimalNumbers correctly (see iOS: formatting decimal numbers).
But maybe it can create a NSDecimalNumber correctly from a string.

I think the problem is not in the limit of the NSNumberFormatter, it´s in the limit of the double itself.
The max value of a double in Objective-C is 15 digits, I think that is a good clue about what is going on in your program.
I think that when you are doing this¨
[NSNumber numberWithDouble:[tempString doubleValue]]];
You are limiting the value of the NSNumber, because doubleValue is going to have a limit!

Related

NSNumberFormatter: Displaying zero as last digit starting from a string like 25.0

I have a string that represents a float, for example 2400.0. I want to format it as digit (2,400.0) and I need to keep the zero after the digit symbol.
NSString* theString = #"2400.0";
// I convert the string to a float
float f = [theString floatValue];
// here I lose the digit information :( and it ends up with 2400 instead of 2400.0
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setNumberStyle:NSNumberFormatterDecimalStyle];
[formatter setUsesSignificantDigits:YES];
[formatter setMinimumFractionDigits:1];
[formatter setMaximumFractionDigits:2];
[formatter setLocale:[NSLocale currentLocale]];
NSString *result = [formatter stringFromNumber:#(f)];
The NSLog of result is 2,400 while I need 2,400.0
How can I obtain the right string?
You probably want to set the minimumFractionDigits to 1 (and your maximumFractionDigits as well in this case).
You also probably don't want to use significant digits. The following code yields the desired output:
NSString *theString = #"2400.0";
float f = [theString floatValue];
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setNumberStyle:NSNumberFormatterDecimalStyle];
[formatter setMinimumFractionDigits:1];
[formatter setMaximumFractionDigits:1];
[formatter setLocale:[NSLocale currentLocale]];
NSLog(#"%#", [formatter stringFromNumber:#(f)]);
Te below solves the issue
NSString *formatString = #"0,000.0";
[formatter setPositiveFormat:formatString];
The number of 0's after decimal will be used for formatting. It works for negative numbers also.
you should dynamically change the format string based on number of digits of the float value before and after decimal point.
Hope it helps.
easy,
then you go to display it just do this:
myLabel.text = #"%0.1f", f;
Use minimumFractionDigits in addition to maximumFractionDigits:
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
formatter.minimumFractionDigits = 1;
formatter.maximumFractionDigits = 1;
XCTAssert([[formatter stringFromNumber:#(2400.0)] isEqualToString:#"2400.0"]);
XCTAssert([[formatter stringFromNumber:#(2400.1)] isEqualToString:#"2400.1"]);

Convert array of NSStrings to array of formatted NSNumbers

I have an array of strings called valuesArray containing values like this: 2913451.0938
I am trying to format those numbers so that I can display them like this: 2,913,451.09
Using the following code I am able to read the values from the array and convert them to NSNumbers (num), and I am also able to create a formatter to define how I want my numbers to be displayed (formatter).
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setNumberStyle:NSNumberFormatterDecimalStyle];
[formatter setMaximumFractionDigits:2];
NSNumber *num = valuesArray[indexPath.row];
NSLog(#"num: %#",num);
NSLog(#"Formatter: %#",formatter);
NSString *forNum = [formatter stringFromNumber:num];
NSLog(#"FormattedNum: %#",forNum);
When I run the code and get to the line NSLog(#"FormattedNum: %#",forNum); I see that it prints null. What am I missing?
The problem in your code is that you retrieve an element from you array of strings valueArray but assign it to an NSNumber typed variable—while the object really is an NSString. When you pass it to the formatter it returns nil (even though it also might crash, it's just undefined behavior).
You have to convert the string to an NSNumber:
NSNumber *num = #([valuesArray[indexPath.row] doubleValue]);
I just checked this code with this value :
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setNumberStyle:NSNumberFormatterDecimalStyle];
[formatter setMaximumFractionDigits:2];
NSNumber *num = #(2913451.0938);
NSLog(#"num: %#",num);
NSLog(#"Formatter: %#",formatter);
NSString *forNum = [formatter stringFromNumber:num];
NSLog(#"FormattedNum: %#",forNum);
It worked fine, no error what so ever as you mentioned.
See the Output :
2013-02-28 21:35:44.417 BrowserModal[4861:403] num: 2913451.0938
2013-02-28 21:35:44.418 BrowserModal[4861:403] Formatter: <NSNumberFormatter: 0x100160840>
2013-02-28 21:35:44.419 BrowserModal[4861:403] FormattedNum: 29,13,451.09
Please clean your target and re-build.
And
Make sure valuesArray[indexPath.row] returns a boxed NSNumber object.
Do as : #([valuesArray[indexPath.row] doubleValue]);

How to format and print float numbers on iOS?

I would like to create a formatted output of a floating point number with correct localization on Cocoa-Touch. The output should be equivalent to that of printf("%<a>.<b>f", n), where <a> is the total number of digits and <f> is the maximum number of fractional digits.
Setup of NSNumberFormatter with <a>=6 and <f>=2: (Platform is iOS 5.1 SDK, Xcode 4.3.3 and the iPhone Simulator 5.1)
NSNumberFormatter *nf = [[NSNumberFormatter alloc] init];
[nf setNumberStyle:NSNumberFormatterDecimalStyle];
[nf setPaddingCharacter:#" "];
[nf setUsesGroupingSeparator:NO];
[nf setLocale:[NSLocale autoupdatingCurrentLocale]];
[nf setUsesSignificantDigits:YES];
[nf setMaximumSignificantDigits:6];
[nf setMaximumFractionDigits:2];
[nf setRoundingMode:NSNumberFormatterRoundFloor];
NSLog(#"Test: %#", [nf stringFromNumber:[NSNumber numberWithDouble:2.64324897]]);
Expected output (with German locale): Test: 2,64
Observed output (with German locale): Test: 2,64324
Other observations:
I have tried to use different values for the fraction digits, e.g. [nf setMaximumFractionDigits:4] or [nf setMaximumFractionDigits:0]. The result is unchanged, it appears that the fraction digits are ignored. Changing the locale to US only changes the , to a ., not the number of fraction digits.
Question: How can I translate the printf-format string correctly to an NSNumberFormatter?
Ryan is not totally wrong. Use the localizedStringWithFormat method:
using objective-c
NSNumber *yourNumber = [nf numberFromString:yourString];
//to create the formatted NSNumber object
NSString *yourString = [NSString localizedStringWithFormat:#"%.2F", yourNumber];
//to create the localized output
using SWIFT 3
let yourString: String
yourString = String.localizedStringWithFormat("%.2F", yourDoubleNumber) //no need for NSNumber Object
A little bit late but it still might help. Good luck!

NSNumberFormatter, appending decimal to calculator from UI

Ok, so I am writing a calculator app now. So far, I'm not having much luck in regard to decimals (my most recent approach hasn't worked well).
-(void) DecimalAdded
{
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setNumberStyle:NSNumberFormatterDecimalStyle];
[formatter setAlwaysShowsDecimalSeparator:YES];
[formatter setGeneratesDecimalNumbers:YES];
[formatter setDecimalSeparator:#"."];
//first convert the float value of CN into NSnumber
NSNumber *nextstepNumFromCNF= [NSNumber numberWithFloat:currentNumber];
//now we have to convert that number into a string
NSString *CNconverted = [formatter stringFromNumber:nextstepNumFromCNF];
NSNumber *CNdecmAddedAndReadyForPars = [formatter numberFromString:CNconverted];
currentNumber = currentNumber*10 + [CNdecmAddedAndReadyForPars floatValue];
CalculatorScreen = [NSMutableString stringWithFormat: #"%#", CNconverted];
I can append the string to the Calculator screen I can say the number is 1, I see "1." as I'm typing. However this is usually converted to 1 during th float conversion (which is correct).
What is this best way to accomplish this?

Formatting a number to show commas and/or dollar sign

I want to format my UILabel with commas or better with a dollar sign and commas (with no decimal).
Here is the code I am using:
IBOutlet UILabel *labelrev
float rev = (x + y)
labelrev.text = [[NSString alloc] initWithFormat:#%2.f",rev];
I get xxxxxxxxx as the output I want to get xxx,xxx,xxx or $xxx,xxx,xxx
How do I do that?
You should definitely use NSNumberFormatter for this. The basic steps are:
Allocate, initialize and configure your number formatter.
Use the formatter to return a formatted string from a number. (It takes an NSNumber, so you'll need to convert your double or whatever primitive you have to NSNumber.)
Clean up. (You know, memory management.)
This code sets up the number formatter. I've done everything that you want except the currency bit. You can look that up in the documentation.
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setNumberStyle:NSNumberFormatterCurrencyStyle];
NSString *groupingSeparator = [[NSLocale currentLocale] objectForKey:NSLocaleGroupingSeparator];
[formatter setGroupingSeparator:groupingSeparator];
[formatter setGroupingSize:3];
[formatter setAlwaysShowsDecimalSeparator:NO];
[formatter setUsesGroupingSeparator:YES];
Next, you want to set up your number and return a formatted string. In your case, we wrap a double in an NSNumber. I do it inline, but you can break it up into two steps:
NSString *formattedString = [formatter stringFromNumber:[NSNumber numberWithFloat:rev];
Don't forget to clean up!
[formatter release];
A quick note about localization:
The NSLocale class provides some useful info about the user's locale. In the first step, notice how I used NSLocale to get a localized grouping separator:
NSString *groupingSeparator = [[NSLocale currentLocale] objectForKey:NSLocaleGroupingSeparator];
(Some countries use a full-stop/period, while others use a comma.) I think there's a way to get a localized currency symbol as well, but I'm not one hundred percent sure, so check the documentation. (It depends upon what your trying to do.)
You will need to use a NSNumberFormatter which supports currency.
NSNumberFormatter *currencyFormatter = [[NSNumberFormatter alloc] init];
[currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
NSLog(#"%#", [currencyFormatter stringFromNumber:[NSNumber numberWithInt:10395209]]);
[currencyFormatter release];
Prints: $10,395,209.00
[formatterCurrency setMaximumFractionDigits:0]
is only way to trancate decimal digits and decimal separator in a NSNumberFormatterCurrencyStyle formatter.
NSNumberFormatter *formatterCurrency;
formatterCurrency = [[NSNumberFormatter alloc] init];
formatterCurrency.numberStyle = NSNumberFormatterCurrencyStyle;
[formatterCurrency setMaximumFractionDigits:0];
[formatterCurrency stringFromNumber: #(12345.2324565)];
result
12,345 $