Is there a quick way to format numbers (e.g., when using appendFormat) so that only enough decimal places are shown? E.g., 4.23100 is shown as 4.231, while 5.0000 is shown as just 5.
Thanks for reading.
Is there a quick way to format numbers (e.g., when using appendFormat) so that only enough decimal places are shown? E.g., 4.23100 is shown as 4.231, while 5.0000 is shown as just 5.
Thanks for reading.
Use %g instead of %f
double n = 1234.5678;
NSString str = [NSString stringWithFormat:@"number is %g", n];
Use %g with the appropriate precision.
double number = 1234.123;
NSLog(@"Number equals: %.8g", number)
As referenced here, the %g conversion will default to 6 significant figures unless a maximum precision is specified. %.7g or larger will all give the desired float.
I couldn't find a built-in way to do this at first, so I built a quick function (below) if anyone is interested. That said, I believe %g (Thanks MSgambel, Roger Gilbrat) and the NSNumberFormatter class (Thanks Inafziger, David Nedrow) do this much more succinctly, so they're probably the better option!
+ (NSString *)trimmedFraction:(float)fraction{
int i=0;
float numDiff=0;
// Loop through possible decimal values (in this case, maximum of 6)
for (i=0;i<=6;i++){
// Calculate difference between fraction and rounded fraction
numDiff=round(fraction*pow(10,i))/pow(10,i)-fraction;
// Check if difference is less than half of the smallest possible value
if (fabsf(numDiff)<(0.5*pow(10,-6))){
break;
}
}
// Return string of truncated fraction
NSString *stringPattern=[NSString stringWithFormat:@"%%0.%df",i];
return [NSString stringWithFormat:stringPattern,fraction];
}
In the code you can specify the maximum number of decimal spaces (e.g., 6 in this case). Then you just send it a fraction and it returns a string with only the relevant decimals. For example, send it 4.231000 and it returns @"4.231", send it 5.000000 and it returns @"5". (Again, probably better to just use %g and NSNumberWithFormatter).
If you store the original values as strings instead of floating-point numbers, the question makes a lot of sense.
I handle this using a category on NSString
:
+ (NSString *) stringForNotANumber {
static NSString *singleton;
if (!singleton) singleton = @"NaN";
return singleton;
}
- (NSUInteger) numberOfDecimalPlaces {
NSString *strValue = self;
// If nil, return -1
if (!strValue) return -1;
// If non-numeric, return -1
NSNumberFormatter *f = [[NSNumberFormatter alloc] init];
[f setMaximumFractionDigits:128];
NSNumber *numValue = [f numberFromString:strValue];
if (!numValue) return -1;
// Count digits after decimal point in original input
NSRange range = [strValue rangeOfString:@"."];
if (NSNotFound == range.location) return 0;
return [strValue substringFromIndex:range.location+1].length;
}
- (NSString *) plus:(NSString *) addend1 {
NSString *addend2 = self;
if (!addend1 || !addend2) return nil;
if (addend1 == [NSString stringForNotANumber] ||
addend2 == [NSString stringForNotANumber])
return [NSString stringForNotANumber];
NSNumberFormatter *f = [[NSNumberFormatter alloc] init];
NSNumber *num1 = [f numberFromString:addend1];
NSNumber *num2 = [f numberFromString:addend2];
if (!num1 || !num2) return [NSString stringForNotANumber];
double sum = num1.doubleValue + num2.doubleValue;
[f setMinimumFractionDigits:MAX(addend1.numberOfDecimalPlaces,
addend2.numberOfDecimalPlaces)];
return [f stringFromNumber:[NSNumber numberWithDouble:sum]];
}