NSNumberFormatter to show a maximum of 3 digits - iphone

I would like to make it so one of my UILabels only shows a maximum of 3 digits. So, if the associated value is 3.224789, I'd like to see 3.22. If the value is 12.563, I'd like to see 12.5 and if the value is 298.38912 then I'd like to see 298. I've been trying to use NSNumberFormatter to accomplish this, but when I set the maximum significant digits to 3 it always has 3 digits after the decimal place. Here's the code:
NSNumberFormatter *distanceFormatter = [[[NSNumberFormatter alloc] init] autorelease];
[distanceFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
[distanceFormatter setAlwaysShowsDecimalSeparator:NO];
[distanceFormatter setMaximumSignificantDigits:3];
I always thought 'significant digits' meant all the digits, before and after the decimal point. Anyway, is there a way of accomplishing this using NSNumberFormatter?
Thanks!

I believe that
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
formatter.usesSignificantDigits = YES;
formatter.maximumSignificantDigits = 3;
will do exactly what you want, i.e. it will always show exactly 3 digits, be it 2 before the decimal and 1 after or 1 before the decimal and 2 after.

Perhaps you also have to set (not sure though):
[distanceFormatter setUsesSignificantDigits: YES];
But in your case it's probably much easier to just use the standard string formatting:
CGFloat yourNumber = ...;
NSString* stringValue = [NSString stringWithFormat: #"%.3f", yourNumber];
(note: this will round the last digit)

Heres a small function I wrote:
int nDigits(double n)
{
n = fabs(n);
int nDigits = 0;
while (n > 1) {
n /= 10;
nDigits++;
}
return nDigits;
}
NSString *formatNumber(NSNumber *number, int sigFigures)
{
double num = [number doubleValue];
int numDigits = nDigits(num);
NSString *format = [NSString stringWithFormat:#"%%%i.%ilf", sigFigures -= numDigits, sigFigures];
return [NSString stringWithFormat:format, num];
}
In my tests, this worked fine.

Related

Elegant method to omit fraction formatting number if number is an integer

I am formatting floating point numbers and right now I have the %0.2f formatter, but I'd like to omit the .00 if the floating point number is an even integer.
Of course I can think of string replacing the .00, but that's crude.
I found that the description of NSNumber also does something similar:
NSNumber *number = [NSNumber numberWithFloat:_paragraphSpacing];
[retString appendFormat:#"margin-bottom:%#px;", number];
This this does hover not limit the post comma digits. if the number is 1234.56789 then the description will output that.
So my question is, is there a just as simple way - possibly without having to create an NSNumber object - to achieve this result?
Since floating-point numbers aren't exact, there's no guarantee that your number will actually be an integer. You can, however, check if it's within a reasonably small distance from an integer value. And of course you don't need an NSNumber for this. (Generally speaking, NSNumber is not used for formatting, its purpose is representing a primitive C type, either integral or floating-point types, using an Objective-C object.)
#include <math.h>
- (NSString *)stringFromFloat:(float)f
{
const float eps = 1.0e-6;
if (abs(round(f) - f) < eps) {
// assume an integer
return [NSString stringWithFormat:#"margin-bottom: %.0fpx", round(f)];
} else {
// assume a real number
return [NSString stringWithFormat:#"margin-bottom: %.2fpx", f];
}
}
Use a formatter:
NSNumberFormatter* formatter= [NSNumberFormatter new];
formatter.numberStyle= NSNumberFormatterDecimalStyle;
formatter.maximumFractionDigits=2;
NSNumber *number = [NSNumber numberWithFloat:_paragraphSpacing];
[retString appendFormat:#"margin-bottom:%#;", [formatter stringFromNumber: number]];
You can use an NSNumberFormatter for this:
static NSNumberFormatter *numberFormatter = nil;
if (numberFormatter == nil) {
numberFormatter = [[NSNumberFormatter alloc] init];
numberFormatter.minimumFractionDigits = 0;
numberFormatter.maximumFractionDigits = 2;
numberFormatter.usesGroupingSeparator = NO;
}
NSString *formattedNumberString = [numberFormatter
stringForNumber:[NSNumber numberWithDouble: _paragraphSpacing]];
You can use C function modff to get the fraction part and test it:
float fractionPart = 0.;
modff(_paragraphSpacing, &fractionPart);
if( fabsf(fractionPart) < 0.01 ) {
// format as integer
[retString appendFormat:#"margin-bottom:%d", (int)_paragraphSpacing];
} else {
// format as float
[retString appendFormat:#"margin-bottom:%0.2f", _paragraphSpacing];
}

Getting numbers from a string in iPhone programming

I have a string. It's always 3 letters long, and it can be counted on to only contain three integers. Say it looks like this:
NSString * numberString = #"123";
Now, I want to extract those numbers from it. 1, 2 and 3. In any other language I'd just fetch the character for each position and parse it, or even cast it.
However, Objective-C doesn't seem to have that. I found some other answer recommending that i use the characterAtIndex method, use numberWithChar on that, and then subtract the number "48" from it, leaving even myself scratching my head at the apparent stupidity of it all.
Is there no other, more elegant way to do this?
I tried using substringWithRange, but apparently there's no method for creating an NSRange, and it's incompatible with CFRangeMake for some reason.
How about [[numberString substringWithRange:NSMakeRange(0,1)] intValue]?
int n=[#"123" intValue];
From this you can get the individual numbers by n/100, n/10 and n%10.
How about this?
NSString * numberString = #"123";
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
NSNumber *number = [formatter numberFromString:numberString];
int n = [number intValue];
(Don't forget to release the formatter after you finish your conversions.)
NSString *numberString = #"123";
int firstDigit = [numberString characterAtIndex:0] - '0';
int secondDigit = [numberString characterAtIndex:1] - '0';
int thirdDigit = [numberString characterAtIndex:2] - '0';
NSLog(#"Your digits are %d, %d, %d", firstDigit, secondDigit, thirdDigit);
If you want to cheat:
char *numberString = [#"123" cStringUsingEncoding:NSASCIIStringEncoding];
printf(#"Your digits are %d, %d, %d\n", numberString[0] - '0',
numberString[1] - '0',
numberString[2] - '0');

iPhone NSNumberFormatter for less than 1 value

I have a floating point value
i.e. 0.0467
Want have a string
05
how can get it? Excluding the decimal point (.).
More precisely, if I have a floating point number, I want to divide it to integral and decimal, preferably into two string parts.
By following this, you will get desired result.
float floatValue = 0.0467;
NSString *str = [NSString stringWithFormat:#"%.2f", floatValue];
str = [str stringByReplacingCharactersInRange:NSMakeRange(0, 2) withString:#""];
NSLog(#"%#", str); // Result will be: 05
fDecimal = 0.04567;
NSString * strDecimal = [NSString stringWithFormat:#"%0.2f", fDecimal];
NSString * strDecimalPart = [strDecimal substringWithRange:NSMakeRange(2, 2)];
The setting you are looking for is called fraction digits:
NSNumberFormatter* f = [[[NSNumberFormatter alloc] init] autorelease;
[f setMaximumFractionDigits:2];
Optionally you can use -[NSNumberFormatter setRoundingMode:] to specify how rounding should be done.

Custom floating decimal points

label.text = [NSString stringWithFormat:#"%.2f",final];
The above statement displays the float value available in the variable "final" with two digits after decimal point.
I want to display number of decimals in depending upon the number i have give to a integer variable like this
label.text = [NSString stringWithFormat:#"%.if",j,final]
Here j is integer variable. Whatever the number i have taken for j that many decimals it should display. I need proper syntax to display the above statement.
The IEEE printf spec that Apple follows states:
A field width, or precision, or both, may be indicated by an asterisk
( '*' ). In this case an argument of type int supplies the field width
or precision.
This means that
label.text = [NSString stringWithFormat:#"%.*f",j,final]
might work, but I have no platform available to test it right now.
NSNumberFormatter has the ability to do what you want. Any of the following methods can be set using a variable before you format your string.
- (void)setMinimumIntegerDigits:(NSUInteger)number
- (void)setMinimumFractionDigits:(NSUInteger)number
- (void)setMaximumIntegerDigits:(NSUInteger)number
- (void)setMaximumFractionDigits:(NSUInteger)number
Data Formatting Guide - Number Formatters
I don't know if there's a one-liner that will do what you want, but you can always do:
NSString* formatString = [NSString stringWithFormat: #"%%.%if", j];
label.text = [NSString stringWithFormat:formatString, final];
You can use NSNumberFormatter,
NSNumberFormatter *nf = [[NSNumberFormatter alloc] init];
[nf setFormatterBehavior:NSNumberFormatterBehaviorDefault];
[nf setNumberStyle:NSNumberFormatterDecimalStyle];
[nf setMaximumFractionDigits:j]; // Set the number of decimal places here
label.text = [nf stringFromNumber:[NSNumber numberWithFloat:final]];
[nf release];

ObjC Formatting Decimal places of Float to string

How do I format a float to string so that if the user enters a number that has 2 or less decimal places then it is formatted to have 2 decimal places, but if the user enters a float that has 2 or more decimal places then all decimal places are shown. e.g.
4.1 => 4.10
1 => 1.00
1.358484 => 1.358484
So therefore the formatting is to 2 decimal places or more if needed.
Hope I made sense.
Try something like this.
BOOL requiresExtraPrecision (double num) {
double roundedToHundredth = round(num * 100.0) / 100.0;
double diff = num - roundedToHundredth;
if (diff < 0) diff = 0.0 - diff;
if (diff < 0.0000001) {
return NO;
} else {
return YES;
}
}
NSString *formatted (double num) {
if (requiresExtraPrecision(num)) {
return [NSString stringWithFormat:#"%F", num];
} else {
NSNumberFormatter *formatter = [[[NSNumberFormatter alloc] init] autorelease];
[formatter setMaximumFractionDigits:2];
[formatter setMinimumFractionDigits:2];
return [formatter stringFromNumber:[NSNumber numberWithDouble:num]];
}
}
As #Carl wrote in a comment to the question, the hard part is deciding when a double needs all of its precision. In this code, I'm assuming that if the double is "close enough" to a rounded number (within a millionth), then we should just display the rounded number.
You might decide to make it stricter (a billionth?) but you'll always have to use some kind of approximation, because some decimals can't be stored precisely as a float. Even though the user may have typed "0.1" at input time, that information is lost when the number is stored as a float.
So, given that you'll have a float that's extremely close to a decimal but not exactly right, you'll have to decide when you think the float is "close enough" to the decimal.
If you need absolute precision (if you're working with money!) then you should consider using an NSDecimal or an NSDecimalNumber instead of a float.
this could work for you:
NSNumber *aFloat = [NSNumber numberWithFloat:1.2]; //try 1.234 ; 1.23 ; 1.2 ; 1. ; 1
NSString *numberString = [aFloat stringValue];
NSRange dot;
dot = [numberString rangeOfString:#"."];
NSString *finalString;
if (dot.location != NSNotFound) {
NSString *decimals = [numberString substringFromIndex:dot.location + dot.length];
if (decimals.length<1){ // ends with "."
finalString = [numberString stringByAppendingString:#"00"];
}else if (decimals.length<2){ // ends with ".n"
finalString = [numberString stringByAppendingString:#"0"];
}else { // 2 or more decimals: no changes
finalString = numberString;
}
}else { // no decimals
finalString = [numberString stringByAppendingString:#".00"];
}
NSLog(#"______._____finalString:%#", finalString );
EDIT (more flexible, it works with variable numbers of decimals):
NSNumber *aFloat = [NSNumber numberWithFloat:1.1235]; //try 1.234 ; 1.23 ; 1.2 ; 1. ; 1
NSString *numberString = [aFloat stringValue];
NSRange dot;
dot = [numberString rangeOfString:#"."];
if (dot.location == NSNotFound) { // no decimals, add a dot
numberString = [numberString stringByAppendingString:#"."];
NSLog(#"__added dot___ numberString:%#", numberString );
}
dot = [numberString rangeOfString:#"."];
NSString *decimals = [numberString substringFromIndex:dot.location + dot.length];
// int initialDecimals = decimals.length;
int numberOfDecimalsTerget = 2;
for (int initialDecimals = decimals.length; initialDecimals<numberOfDecimalsTerget; initialDecimals++) {
numberString = [numberString stringByAppendingString:#"0"];
}
NSLog(#"__END_._____numberString:%#", numberString );