NSNumberFormatter to stop shortening numbers - objective-c

EDIT: Fixed, here is how i did it for furture reference:
NSNumber *inputNumber = [[NSNumber alloc ]initWithDouble:convertValue];
NSNumber *resultNumber = [[NSNumber alloc]initWithDouble:result];
NSNumberFormatter *formatterResult = [[NSNumberFormatter alloc] init];
formatterResult.numberStyle = NSNumberFormatterDecimalStyle;
NSNumberFormatter *formatterInput = [[NSNumberFormatter alloc] init];
formatterInput.numberStyle = NSNumberFormatterDecimalStyle;
[formatterResult setNumberStyle:NSNumberFormatterDecimalStyle];
[formatterResult setMaximumFractionDigits:6];
[formatterInput setNumberStyle:NSNumberFormatterDecimalStyle];
[formatterInput setMaximumFractionDigits:6];
//These four lines are the one fixing the issue.
NSString *formattedResultString = [formatterResult stringFromNumber:(NSNumber*)resultNumber];
NSString *formattedInputString = [formatterInput stringFromNumber:(NSNumber*)inputNumber];
NSString *formelString = [[NSString alloc]initWithFormat:
#" %# %# =", formattedInputString, convertFromName];
formelLabel.text = formelString;
NSString *resultString = [[NSString alloc]initWithFormat:
#" %# %#",formattedResultString, convertToName];
resultLabel.text = resultString;
----------ORIGINAL QUESTION------------
So I have a problem with NSNumberFormatter shortening numbers too much, and also not displaying decimals when the main number is over 8 digits.
Problem described in following picture:
<- Working, but shortening to three decimals. (And rounding up, which is done mathematically correct)
And then the problems: (Right-most picture is correct)
As you can see, the bottom image just ignores the decimals completely. What code do I need to add/change for this to work properly?
Here is the relevant code:
[super viewDidLoad];
_convertFrom = #[#"MTPA", #"MMcf/day",
#"Mill.Sm3/day", #"MMBTU/day", #"Boe/day",#"ton LNG/day", #"GJ/day"];
_convertTo = #[#"MTPA", #"MMcf/day",
#"Mill.Sm3/day", #"MMBTU/day", #"Boe/day", #"ton LNG/day", #"GJ/day"];
_convertRates = #[ #1.0f, #133.3333333f, #3.775579545f,
#137333.3333f, #23747.68013, #1716.17252, #147247.6022];
//some place down in the code:
-(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
[self updateConversionLabel];
}
- (void)updateConversionLabel
{
float convertFrom = [[_convertRates objectAtIndex:[picker selectedRowInComponent:0]] floatValue];
float convertTo = [[_convertRates objectAtIndex:[picker selectedRowInComponent:1]] floatValue];
NSNumberFormatter *fmt = [NSNumberFormatter new];
float input = [fmt numberFromString:inputText.text].floatValue;
float to = convertTo;
float from = convertFrom;
float convertValue = input;
float relative = to / from;
float result = relative * convertValue;
NSString *convertFromName = [_convertFrom objectAtIndex:[picker selectedRowInComponent:0]];
NSString *convertToName = [_convertFrom objectAtIndex:[picker selectedRowInComponent:1]];
NSNumber *inputNumber = [[NSNumber alloc ]initWithFloat:convertValue];
NSNumber *resultNumber = [[NSNumber alloc]initWithFloat:result];
NSNumberFormatter *formatterResult = [[NSNumberFormatter alloc] init];
formatterResult.numberStyle = NSNumberFormatterDecimalStyle;
NSNumberFormatter *formatterInput = [[NSNumberFormatter alloc] init];
formatterInput.numberStyle = NSNumberFormatterDecimalStyle;
NSString *formattedResultString = [formatterResult stringFromNumber:(NSNumber*)resultNumber];
NSString *formattedInputString = [formatterInput stringFromNumber:(NSNumber*)inputNumber];
NSString *formelString = [[NSString alloc]initWithFormat:
#" %# %# =", formattedInputString, convertFromName];
formelLabel.text = formelString;
NSString *resultString = [[NSString alloc]initWithFormat:
#" %# %#",formattedResultString, convertToName];
resultLabel.text = resultString;
}
I'd assume the problem/fix is in this code.

EDIT: Fixed, here is how I did it for future reference:
NSNumber *inputNumber = [[NSNumber alloc ]initWithDouble:convertValue];
NSNumber *resultNumber = [[NSNumber alloc]initWithDouble:result];
NSNumberFormatter *formatterResult = [[NSNumberFormatter alloc] init];
formatterResult.numberStyle = NSNumberFormatterDecimalStyle;
NSNumberFormatter *formatterInput = [[NSNumberFormatter alloc] init];
formatterInput.numberStyle = NSNumberFormatterDecimalStyle;
[formatterResult setNumberStyle:NSNumberFormatterDecimalStyle];
[formatterResult setMaximumFractionDigits:6];
[formatterInput setNumberStyle:NSNumberFormatterDecimalStyle];
[formatterInput setMaximumFractionDigits:6];
//These four lines are the one fixing the issue.
NSString *formattedResultString = [formatterResult stringFromNumber: (NSNumber*)resultNumber];
NSString *formattedInputString = [formatterInput stringFromNumber:(NSNumber*)inputNumber];
NSString *formelString = [[NSString alloc]initWithFormat:
#" %# %# =", formattedInputString, convertFromName];
formelLabel.text = formelString;
NSString *resultString = [[NSString alloc]initWithFormat:
#" %# %#",formattedResultString, convertToName];
resultLabel.text = resultString;

Real arithmetic is precise. Any computer arithmetic has limited range - how many digits can be represented; and in the case of fractions inaccuracies due to the use of decimal factions by us humans and binary fractions by computers.
In your code you are using float which is a 32-bit binary floating point number with an precision of around 6 decimal digits and a range roughly from 10^-38 to 10^38. Your numbers are up to 9 digits.
Try using double thoughtout (and doubleValue etc.) which is a 64-bit binary floating point with a precision of around 15 decimal digits. You may still find the numbers don't come out as you wish, and for that you will need to look more into how to format numbers, but you should get the precision you are after.
If you need more precision, and decimal floating point as well, look at NSDecimalNumber.
See 32-bit floating point and 64-bit floating point for more details.

Related

How to sum two elements of the array?

NSMutableArray *array = [NSMutableArray arrayWithObjects:#"22,343", #"44,323",#"34,5678",#"22,725", nil];
i have this array and I want to sum two values this array.
like this array[0] + array [1]
how to sum this elements?
thanks !!
Solution is
NSString *strVaue1 = [array[0] stringByReplacingOccurrencesOfString:#"," withString:#""];
NSString *strVaue2 = [array[1] stringByReplacingOccurrencesOfString:#"," withString:#""];
NSUInteger arrValue1 = [strVaue1 integerValue];
NSUInteger arrValue2 = [strVaue2 integerValue];
NSUInteger sum = arrValue1 + arrValue2;
NSNumberFormatter *fmt = [[NSNumberFormatter alloc] init];
[fmt setNumberStyle:NSNumberFormatterDecimalStyle]; // to get commas (or locale equivalent)
[fmt setMaximumFractionDigits:0]; // to avoid any decimal
NSString *result = [fmt stringFromNumber:#(sum)];
NSLog(#"The result is - %#",result);
The printed result is
The result is - 66,666

ios7 NSNumberFormatter decimal style unexpected output

NSNumberFormatter is returning garbage data. The variable of interest is milesString at the bottom. It is rounding to 2 instead of 1.6388. I threw in the debugger info and also added the debugging code for testString and num2. For reference, DistanceFormatter is static, not modified anywhere but this function. I've tried replacing it with a local instance to see if the static object was causing the problem (it wasn't). Another note, I got this error when I wasn't using a roudingMode.
-(NSString *)distanceStringFromLocation:(CLLocation *)location {
if (!DistanceFormatter) {
DistanceFormatter = [NSNumberFormatter alloc];
[DistanceFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
DistanceFormatter.roundingMode = NSNumberFormatterRoundCeiling;
DistanceFormatter.minimumFractionDigits = 0;
DistanceFormatter.maximumFractionDigits = 4;
}
CLLocationDistance distance = [_location distanceFromLocation:location];
distance = distance / 1000;
NSLocale *locale = [NSLocale currentLocale];
BOOL isMetric = [[locale objectForKey:NSLocaleUsesMetricSystem] boolValue];
if (isMetric) {
return [NSString stringWithFormat:#"%# kilometers away", [DistanceFormatter stringFromNumber:[NSNumber numberWithFloat:distance]]];
} else {
CGFloat miles = 0.621371 * distance; //miles = (CGFloat) 1.63877738
NSNumber *num = [NSNumber numberWithFloat:miles]; //num = (__NSCFNumber *)(float)1.63878
NSString *testString = [NSString stringWithFormat:#"%f", miles]; //testString = (__NSCFString *) #"1.63877"
NSNumber *num2 = [DistanceFormatter numberFromString:testString]; //num2 = (NSNumber *)nil
NSString *milesString = [DistanceFormatter stringFromNumber:num]; //milesString = (__NSCFString *)#"2"
return [NSString stringWithFormat:#"%# miles away", milesString];
}
}
You have allocated, but not initialized the date formatter.
DistanceFormatter = [NSNumberFormatter alloc];
should be
DistanceFormatter = [[NSNumberFormatter alloc] init];
With that change you get the result milesString = #"1.6388" .

Objective C remove trailing zeros after decimal place

I am trying to get number in 2 decimal places with trailing zeros.
e.g
11.633-> 11.63
11.630-> 11.63
11.60-> 11.6
11-> 11
12928.98-> 12928.98
for this I written below line
#define kFloatFormat2(x) [NSString stringWithFormat:#"%g", [[NSString stringWithFormat:#"%.2f", x] floatValue]]
NSNumber *number1 = [NSNumber numberWithDouble:12928.98];
NSLog(#"number1:%#", number1);
NSString *string1 = kFloatFormat2([number1 floatValue]);
NSLog(#"string1:%#", string1);
the output of above prints
number1:12928.98
string1:12929
Why it prints 12929 value for string1
I want it as 12928.98.
Have you tried using a number formatter?
NSNumberFormatter *formatter = [[NSNumberFormatter alloc]init];
[formatter setNumberStyle:NSNumberFormatterDecimalStyle];
[formatter setUsesGroupingSeparator:NO];
[formatter setMaximumFractionDigits:fractionDigits];
[formatter setMinimumFractionDigits:fractionDigits];
Now do something like
NSNumber *x = #23423;
NSString *value = [formatter stringFromNumber:x];
NSLog(#"number = %#, value);
You macro makes no sense. Just make it:
#define kFloatFormat2(x) [NSString stringWithFormat:#"%.2f", [x floatValue]]
where x is an NSNumber. And then you would call it like this:
NSString *string1 = kFloatFormat2(number1);
Or just do this:
double x = 12928.98;
NSLog(#"number = %.2f", x);

Space for every three digits

How can I get a simple comma every 3 digits in my result strings?
The code is as follows:
float convertFrom = [[_convertRates objectAtIndex:[picker selectedRowInComponent:0]] floatValue];
float convertTo = [[_convertRates objectAtIndex:[picker selectedRowInComponent:1]] floatValue];
float input = [inputText.text floatValue];
float to = convertTo;
float from = convertFrom;
float convertValue = input;
float relative = to / from;
float result = relative * convertValue;
NSString *convertFromName = [_convertFrom objectAtIndex:[picker selectedRowInComponent:0]];
NSString *convertToName = [_convertFrom objectAtIndex:[picker selectedRowInComponent:1]];
NSString *resultString = [[NSString alloc]initWithFormat:
#" %.4f %#",result, convertToName];
resultLabel.text = resultString;
NSString *formelString = [[NSString alloc]initWithFormat:
#" %.4f %#=", convertValue, convertFromName];
formelLabel.text = formelString;
This code makes a lot of digits, displayed in a block of text, which is not the most practical way to use the data. How can I implement commas in this code?
For example, 1234567 would be 1 234 567 or 1'234'567.
Use NSNumberFormatter.
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
formatter.numberStyle = NSNumberFormatterDecimalStyle;
NSString *formattedString = [formatter stringFromNumber:someNumberValue];
where someNumberValue is an NSNumber object with the number.
This will format the number properly for the user's chosen region formatting.
You can control the number of digits after the decimal if you wish. See the docs for NSNumberFormatter for more details.

NSNumberFormatter leading 0's and decimals

Is there any way to format an NSNumber with leading 0's and decimals? For example, I need to have the ability to write 4.5 as well as 000. Currently I have it where it will allow decimals, but not leading 0's.
NSNumberFormatter *f = [[NSNumberFormatter alloc] init];
f.numberStyle = NSNumberFormatterNoStyle;
NSString *myString = [f numberFromString:#"4.5"];
NSLog(#"myString: %#",myString);
NSString *myOtherString = [f numberFromString:#"000"];
NSLog(#"myOtherString:%#",myOtherString);
The output from above would be: 'myString:4.5' and 'myOtherString:0'. I need to be able to do both '4.5' and '000' as output.
I have looked at Apple's "Data Formatting Guide" without much success.
Note that [f numberFromString:#"4.5"] returns an NSNumber* not a NSString*
You want something like this:
NSNumberFormatter *f = [[NSNumberFormatter alloc] init];
f.numberStyle = NSNumberFormatterNoStyle;
NSNumber *myNumber;
NSString *myString;
myNumber = [f numberFromString:#"4.5"];
[f setNumberStyle:kCFNumberFormatterDecimalStyle];
myString = [f stringFromNumber:myNumber];
NSLog(#"myString: %#",myString);
myNumber = [f numberFromString:#"000"]; // Note that the extra zeros are useless
[f setFormatWidth:3];
[f setPaddingCharacter:#"0"];
myString = [f stringFromNumber:myNumber];
NSLog(#"myString: %#",myString);
NSLog output:
myString: 4.5
myString: 000
If you don't have strings to start with just create number like:
myNumber = [NSNumber numberWithFloat:4.5];
myNumber = [NSNumber numberWithInt:0];
Or just use standard formatting:
myString = [NSString stringWithFormat:#"%.1f", [myNumber floatValue]];
myString = [NSString stringWithFormat:#"%03d", [myNumber intValue]];
Or if you don't need an NSNumber representation just use standard formatting :
myString = [NSString stringWithFormat:#"%.1f", 4.5];
myString = [NSString stringWithFormat:#"%03d", 0];
You could try something like:
NSString *myString = [NSString stringWithFormat:#"%03f", [myNSNumber floatValue]];
This, following the printf format, will print your number forcing at least 3 digits to be printed and padding with '0's any empty space.
How about this as a variation on theme for the 000's
NSNumber *myNumber;
NSString *myString =#"000" ;
NSString * myStringResult;
NSNumberFormatter *f = [[NSNumberFormatter alloc] init];
f.numberStyle = NSNumberFormatterNoStyle;
[f setHasThousandSeparators:FALSE]; //-- remove seperator
[f setMinimumIntegerDigits:[myString length ]]; //-- set minimum number of digits to display using the string length.
myNumber = [f numberFromString:myString];
myStringResult = [f stringFromNumber:myNumber];
NSLog(#"myStringResult: %#",myStringResult);
Since this is asked often and Apple's docs suck, this is the answer that people will be looking for. The link below has two solutions. One using NSString stringWithFormat: and the other using NSNumberFormatter.
https://stackoverflow.com/a/11131497/1058199