Best NSString format for displaying long decimal numbers? - ios

What is the best NSString format for displaying long decimal numbers? I get undesirable rounding that occurs when I try something like:
[NSString stringWithFormat:#"%g", calcResult];
Ideally, I would like the format:
xxx,xxx.xxxxxxxxxxxxxx
with a limit on total number of places collectively between the whole and decimal numbers.
So for example, if that limit were 10 places, the following would be the desired format:
1,234.567891
or
1,234,567.891
Thanks in advance.

NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
// This style turns on locale-specific thousands separators.
// US English uses commas.
formatter.numberStyle = NSNumberFormatterDecimalStyle;
// This specifies exactly 10 decimal digits of output.
formatter.usesSignificantDigits = YES;
formatter.minimumSignificantDigits = 10;
formatter.maximumSignificantDigits = 10;
NSLog(#"%#", [formatter stringFromNumber:#(1234.567891)]);
NSLog(#"%#", [formatter stringFromNumber:#(1234567.891)]);
Output:
2013-12-04 17:36:32.372 numberFormatter[70896:303] 1,234.567891
2013-12-04 17:36:32.373 numberFormatter[70896:303] 1,234,567.891

To convert a number value using grouping and decimal separator according to your desired locale you definitely need to use NSNumberFormatter.
On an instance of NSNumberFormatter you can set your desired rounding algorithm (number of digits, rounding behavior). Also it will automatically use current locale for you. You'll be left with a simple
[numberFormatter stringFromNumber:myNumber];
Note that you'll be able to use different formatters that have different rounding rules: 2/3 can be printed as 0.6, 0.7, 0.67 and so on. If your number is inherently decimal, like the numbers that occur in finance, you can consider using NSDecimalNumber to hold the number value. Once set, an instance of NSDecimalNumber will remember the exact number of decimal digits and if you print it with a generic NSNumberFormatter, you'll never lose significant digits.
This is how you can limit the total number of digits to 10:
Given a decimal number, divide or multiply it by 10 until it's between 0.1 and 1.
Round it to 10 digits after decimal point.
Reverse the procedure in 1.
Now you have a decimal number with exactly 10 significant digits.
Technically, you're able to convert NSDecimalNumber to a string without using an NSNumberFormatter by -descriptionWithLocale:. But I don't think it can do groupings.
And if your code isn't supposed to be internationalized, you can also do
[NSString stringWithFormat:#"%#", decimalNumber];

Related

NSNumberFormatter stringFromNumber returning 1,000,000,000 for input 999999999

When I try to convert number 999999999 to string using NSNumberFormatter, I am getting wrong value. It returns 1,000,000,000 instead of 999,999,999.
Here is the code that I use.
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setUsesSignificantDigits:YES];
[numberFormatter setNumberStyle: NSNumberFormatterCurrencyStyle];
[numberFormatter setLocale:[NSLocale systemLocale]];
[numberFormatter setCurrencySymbol:#""];
numberAsString = [numberFormatter stringFromNumber:[NSDecimalNumber decimalNumberWithString:#"999999999" ]];
NSLog(#"Currency String %#",numberAsString);
You specified to use significant digits, but didn't say how many to use. For example, if you add the following, you get the result you were expecting:
[numberFormatter setMaximumSignificantDigits:9];
So, if you're going to use significant digits, specify how many you want to use. Or don't use significant digits at all.
You enabled usesSignificantDigits. Default value for maximumSignificantDigits is 6. Which means every number with more than 6 significant digits will be rounded to have less than 6 significant digits.
999 999 999 has 9 significant digits. So it will be rounded to 1 000 000 000
You probably don't want to set usesSignificantDigits at all.
Here is a good explanation what significant digits do with NSNumberFormatter.

Converting a string to int is dropping the leading 0 and makes it think it is an octal number (xcode iOS)

I'm a little stumped on this one so appreciate the assistance of the experts on this forum, please.
My app has a text field where the user enters a 10 digit number, that number can start with a 0, e.g. 0727158880
I need to convert that number to an int so I can increment it by 1 each time my app goes through a loop of doing some stuff. But when I convert the string to an int it drops the leading 0 and returns just: 727158880
I "think" this is because it sees the leading 0 and thinks it is an octal number, but I don't want it to do that. Any ideas how I can keep the number as entered by the user and then incremement it?
Thanks!
This has nothing to do with octal numbers at all. You are converting a string to an integer. Integers are just numbers, they have no digits, they have no leading zero digits.
If you enter "man printf" into terminal it will tell you all the formats for printing numbers, and you can tell it to print an integer in 10 digits with leading zeroes.
A number cannot have leading 0. Hence you know there is 10 digits number. A solution is
NSInteger number = [str integerValue];
number++;
NSString *newStr = [NSString stringWithFormat:#"%010d", number];

Remove trailing zeros of a double only when necessary

Im making a calculator app and I am using a double for the precision. I didn't want the extra zeros and the decimal to be displayed so I changed the place holder token to "%.f". Because I did this if I do a problem on the calculator that does involve decimals they don't show up.
My question is basically if there is any way to have the %.f be used only when its necessary. If there is no way, what do you recommend doing to make it so I only have a decimal when its actually needed. Thanks.
You probably want to use NSDecimarlNumber, but to answer your question, you can user NSNumberFormatter to format the output for a double.
double someNumber = 1.9;
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setNumberStyle:NSNumberFormatterDecimalStyle];
NSLog(#"%#",[formatter stringFromNumber:[NSNumber numberWithDouble:someNumber]]);
My output
2014-01-13 11:30:41.429 DTMTestApp[23933:907] 1.9
For a calculator consider using NSDecimalNumber combined with NSNumberFormatter. There are going to be lot's of problems using floating point. Consider: (2 / 3.000000001) * 3.000000001, the result will not necessarily be exactly 2.

How to place a currency symbol prefix or postfix with a string?

I'm wondering if there is any official way to put a currency symbol to the left or to the right from the money amount, depending of the region and the currency itself?
For example, if it's a $ sign, it should be to the left of the amount, as $20. If it's, for instance, € sign, then it should go as 20€.
I've found a simple way, I just check with If statement if the currency symbol is $ and append it to the left or to the right to my NSString. But this looks a bit lame like a crutch method.
I was unable to find some more convenient way. Is there any?
Thank you.
Apples official way ......
You need to use NSNumbers and NSNumberFormatter to convert the value to a currency and return a string representing it. This can be used in our labels e.t.c. someDouble refers to the number you wish to convert to a currency format.
NSNumber *currencyValue = [NSNumber numberWithDouble:someDouble];
NSNumberFormatter *formater = [[NSNumberFormatter alloc] init];
[formater setNumberStyle:NSNumberFormatterCurrencyStyle];
NSString *currencyString = [formater stringFromNumber:currencyValue];
NOTE: you may need to play around with the setLocale to get it to display the correct currency for a given region.

Change default locale behavior for currency formatting

I am facing a strange problem. My app relies on a double conversion:
currency string -> number -> currency string
Basically, the single conversions are realized through the built-in localization functions of iOS. I recently found that the app does not work properly when the user uses CHF as currency. Apparently the default for this locale is to round all currency values to the nearest 5 cents. (eg. CHF 1.28 will become CHF 1.30, and 1.21 CHF will become CHF 1.20).
For a bunch of reasons it's easier for me to solve the formatting convention than solve the bug for that only locale.
Do you know a way to force the conversion to use a more detailed rounding approach (eg. 0.01 instead of 0.05) for every locale?
Thank you!
I found an interesting solution:
currencyFormatter = [[NSNumberFormatter alloc] init];
[currencyFormatter setGeneratesDecimalNumbers:YES];
[currencyFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
[currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
// This will force the rounding behavior:
[currencyFormatter setRoundingIncrement:[NSNumber numberWithFloat:0.01]];

Resources