I have an NSForm that is being used to display content to the user. The form can either be updated via the application by connecting to an web hosted XML file or manually edited by the user. Through Interface Builder I have set each form value to be formatted through an NSNumberFormatter to make the display of the data easier to read. The NSNumberFormatter is only inserting the thousands separator.
Because the data can be manually edited by the user, I am extracting the stringValue of the NSForm fields. I have noticed that when I perform this function, it also grabs the commas that have been injected into the string. I need to do some math with these values and it's causing a problem when trying to call NSString intValue or NSString floatValue. Anyone have any ideas?
I was thinking that I might have to "pre-parse" the string to remove the commas before converting it to a float or int value.
NSNumberFormatter can work backwards too:
NSNumber *n = [formatter numberFromString:#"123,456.78"];
float x = [n floatValue];
Related
I'm having a serious dispute with NSNumberFormatter, and even after going through its extensive documentation, I haven't quite been able to wrap my head around a pretty straightforward issue that I encountered. I hope you guys can help me out.
What I have: an NSDecimalNumber representing a calculation result, displayed in a UITextField
What I need: Scientific notation of that result.
What I'm doing:
-(void)setScientificNotationForTextField:(UITextField*)tf Text:(NSString*)text {
NSString* textBefore = text;
// use scientific notation, i.e. NSNumberFormatterScientificStyle
NSNumberFormatter* formatter = [[NSNumberFormatter alloc] init];
//[formatter setGeneratesDecimalNumbers:YES];
[formatter setNumberStyle:NSNumberFormatterScientificStyle];
NSDecimalNumber* number = (NSDecimalNumber*)[formatter numberFromString:text];
tf.text = [number descriptionWithLocale:[[Utilities sharedUtilities] USLocale]];
NSString* textAfter = tf.text;
// DEBUG
NSLog(#"setScientificNotation | text before = %#, text after = %#", textBefore, textAfter);
[formatter release];
}
What happens:
A certain result may be 0.0099. textBefore will hold that correct value. If I don't tell the formatter to generate decimal numbers (commented out in the above snippet), it will create an NSNumber from an NSDecimalNumber which creates a false result and turns textAfterinto 0.009900000000000001 - a rounding error due to the reduced precision of NSNumber over NSDecimalNumber.
If I do tell the NumberFormatter to generate decimals, it will still create the wrong result . And what's more, where before it would insert the exponent notation (e.g. "1.23456e-10"), it would now generate (and thus display) the full decimal number, which is not what I want.
Again, I'd like to have the formatter use NSDecimalNumber so it doesn't falsify results plus have exponent notation where necessary.
Am I using the class wrong? Did I misinterpret the documentation? Can someone explain why this happens and how I can create the behavior I want? I will of course continue researching and update if I find anything.
You can't just cast an NSNumber to an NSDecimalNumber and expect it to work. If your number is not too complex, you can ditch NSNumberFormatter and try using this instead:
NSDecimalNumber* number = [NSDecimalNumber decimalNumberWithString:text];
That will give you an actual NSDecimalNumber instance, with its precision.
Unfortunately, setGeneratesDecimalNumbers: doesn't work properly. It's a known bug.
If your number is too complex to work with decimalNumberWithString:, you're probably out of luck with Apple's APIs. Your only options are either parsing the string manually into something NSDecimalNumber can understand or performing some post-processing on the imprecise value given to you by NSNumberFormatter.
Finally, if you really want a number in scientific notation, why not just use the number formatter you just used? Just call stringFromNumber: to get the formatted value.
I have a value being stored as an NSDecimalNumber and when I convert it to a double it's losing precision.
For the current piece of data I'm debugging against, the value is 0.2676655. When I send it a doubleValue message, I get 0.267665. It's truncating instead of rounding and this is wreaking havoc with some code that uses hashes to detect data changes for a syncing operation.
The NSDecimalNumber instance comes from a third-party framework so I can't just replace it with a primitive double. Ultimately it gets inserted into an NSMutableString so I'm after a string representation, however it needs to be passed through a format specifier of "%.6lf", basically I need six digits after the decimal so it looks like 0.267666.
How can I accomplish this without losing precision? If there's a good way to format the NSDecimalNumber without converting to a double that will work as well.
The NSDecimalNumber instance comes from a third-party framework so I
can't just replace it with a primitive double.
Yes you can. NSDecimalNumber is an immutable subclass of NSNumber, which is a little too helpful when it comes to conversion:
double myDub = [NSDecimalNumber decimalNumberWithDecimal:[[NSNumber numberWithDouble:((double)0.2676655)] doubleValue]];
Ultimately it gets inserted into an NSMutableString so I'm after a
string representation, however it needs to be passed through a format
specifier of "%.6lf", basically I need six digits after the decimal so
it looks like 0.267666.
Double precision unfortunately does not round, but getting a string value that's off by one-millionth is not that big of a deal (I hope):
NSDecimalNumber *num = [NSDecimalNumber decimalNumberWithDecimal:[[NSNumber numberWithDouble:((double)0.2676655)] decimalValue]];
NSString *numString = [NSString stringWithFormat:#"%.6lf", [num doubleValue]];
NSLog(#"%#",numString);
I think that your are on a wrong path and somewhere lost in what to do.
First of all, keep in mind that in objective-c lond double is not supported, so you might better want to use something like %f instead of %lf.
[to be found in the documentation library under "Type encodings" of the objective c runtime programming guide]
Then I would rather expect that the value is show as being truncated, as the doubleValue returns an approximate value but the range you are using is still within the correct range.
You should use a simple formatter instead of moving numbers around, like:
// first line as an example for your real value
NSDecimalNumber *value = [NSDecimalNumber decimalNumberWithString:#"0.2676655"];
NSNumberFormatter *numFmt = [[NSNumberFormatter alloc] init];
[numFmt setMaximumFractionDigits:6];
[numFmt setMinimumFractionDigits:6];
[numFmt setMinimumIntegerDigits:1];
NSLog(#"Formatted number %#",[numFmt stringFromNumber:value]);
This has another benefit of using a locale aware formatter if desired. The result of the number formatter is the desired string.
I have a class holding various types of numeric values. Within this class I have a couple of helper methods that are used to output descriptor text for display within my application.
This descriptor text should always appear as an integer or float, depending on the definition of the particular instance.
The class has a property, DecimalWidth, that I use to determine how many decimals to display. I need help writing a line of code that displays the numeric value, but with a fixed number of decimals, (0 is a possibility, and in such a case the value should be displayed as an integer.)
I am aware that I can could return a value like [NSString stringWithFormat:#"%.02f", self.Value] but my problem is that I need to replace the '2' in the format string with the value of DecimalWidth.
I can think of couple ways of solving this problem. I could concat a string together and that is as the format string for the outputted string line. Or, I could make a format string within a format string.
These solutions sound hideous and seem rather inefficient, but maybe these are the best options that I have.
Is there an elegant way of constructing a dynamic formatting string where the output is a fixed decimal width number but the specified decimal width is dynamic?
That doesn't sound hideous or inefficient to me.
[NSString stringWithFormat:[NSString stringWithFormat:#"%%.%df", DecimalWidth], self.Value]
In fact I think it is rather elegant.
However one solution for the problem is definitely question suggested by #lulius caesar,
But one good way is also using NSNumberFormatter. Below is a sample code you can use to generate decimal values with fixed decimal number
NSNumberFormatter *numberFormatter=[[NSNumberFormatter alloc] init];
[numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
[numberFormatter setMinimumFractionDigits:DecimalWidth];
[numberFormatter setMaximumFractionDigits:DecimalWidth];
NSString * decimalString = [numberFormatter stringFromNumber:[NSNumber numberWithFloat:self.value]]]
I'm struggling with this issue, and I couldn't find any resource for it :
I have an NSNumber that I want to display in an UITextField, so the user can edit it.
So I need to convert this NSNumber to an NSString, like this :
float value -> desired string value
1.0000000... -> 1
10.000000... -> 10
1.1230000... -> 1.123 or 1,123 depending on the locale
1000000.0... -> 1000000
I've tried to use NSNumberFormatter, but then I get spaces or comas for big numbers :
1000000.0... -> 1,000,000 or 1 000 000 depending on the locale
I also tried
[NSString stringWithFormat:#"%g", val]
But then for big numbers I have a scientific expression :
1000000.0 -> 1e+06
Did somebody have a successful experience with this ?
NSNumberFormatter has such method as :
- (void)setGroupingSeparator:(NSString *)string
I think, you can return to variant where you has:
1000000.0... -> 1,000,000 or 1 000 000 depending on the locale
and set additional parameter using that function:
[formatter setGroupingSeparator:#""];
Or moreover try this method:
[formatter setUsesGroupingSeparator:NO];
NSNumberFormatter is the solution, you were on the right path.
But:
the formatting it uses depends on the locale (either it uses the default locale if you don't override it, or you can set the locale used by the NSFormatter), because the NSLocale information also carries the Region Formatting info (formatting numbers using the US locale or the FR locale leads to different formats and different representations)
You can customize the formatting by tuning the options of NSNumberFormatter, like changing the grouping separators used, changing the decimal separator, etc.
This way you can really customize the way the NSNumberFormatter represents the numeric value into a string.
try converting nsnumber value to NSInteger or CGFloat and store it in the new variables. Then set the converted variables to uitextfield.
CGFloat floatNumber = [numberInNSNumber floatValue];
textfield.text = [NSString stringWithFormat:#"%0.2f",floatNumber];
I think it should work for you..!!
So when I convert a double to a string using something like this:
double number = 1.1;
text = [[NSString alloc] initWithFormat:#"%f", number];
The variable text ends up printing something like this: 1.100000. I realize that this is because of the way the computer stores the value however I need an easy way to remove those extra zeros and, if need be, the decimal as well if the number turns out to an integer.
Thanks!
Try to look at NSNumber and NSNumberFormatter with it's usesSignificantDigits property. It is probably what you are looking for.