So lets say I have the following:
NSNumber *num = [NSNumber numberWithDouble:12345678901234567];
Now I would like for that to be formatted as a string in the following format: 1.234567E16
I have tried both:
formatter.numberStyle = NSNumberFormatterScientificStyle;
formatter.maximumFractionDigits = 6;
and
formatter.positiveFormat = #"0.00000E0";
But my result is always 1.23457E16
Why does it skip the 6?
If I change it to maximumFractionDigits = 7 it would print 1.234568E16
What am I doing wrong?
It's most likely rounding the 6 up to 7.
I do not suggest using formatter.roundingMode = NSNumberFormatterRoundDown; since that is a hack.
What you need to do to force 6 digits is set the maximum and the minimum number of fractional digits.
[formatter setMaximumFractionDigits:6];
[formatter setMinimumFractionDigits:6];
Related
I am trying to separate the left and right numbers from a float so I can turn each into a string. So for example, 5.11, I need to be able to turn 5 into a string, and 11 into another string.
// from float: 5.11
NSString * leftNumber = #"5";
NSString * rightNumber = #"11";
From this, I can turn 5.11 into 5' 11".
One way:
Use stringWithFormat to convert to string "5.11".
Use componentsSeparatedByString to seperate into an array of "5" and "11".
Combine with stringWithFormat.
You could use NSString stringWithFormat and math functions for that:
float n = 5.11;
NSString * leftNumber = [NSString stringWithFormat:#"%0.0f", truncf(n)];
NSString * rightNumber = [[NSString stringWithFormat:#"%0.2f", fmodf(n, 1.0)] substringFromIndex:2];
NSLog(#"'%#' '%#'", leftNumber, rightNumber);
However, this is not ideal, especially for representing lengths in customary units, because 0.11 ft is not 11 inches. You would be better off representing the length as an integer in the smallest units that you support (say, for example, 1/16-th of an inch) and then convert it to the actual length for display purposes. In this representation 5 ft 11 in would be 5*12*16 + 11*16 = 1136.
You could use a number formatter as such
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
formatter.numberStyle = NSNumberFormatterDecimalStyle;
formatter.decimalSeparator = #"'";
formatter.positiveSuffix = #"\"";
formatter.alwaysShowsDecimalSeparator = true;
NSString *numberString = [formatter stringFromNumber:#(5.11)];
// Output : 5'11"
I want to use a number formatter to generate my output, so the number is automatically formatted for the user's locale, but I want it to work like "%+.1f" does in printf(), that is always have a sign specified.
NSNumberFormatter *nf = [[NSNumberFormatter alloc] init];
nf.numberStyle = NSNumberFormatterDecimalStyle;
nf.maximumFractionDigits = 1;
double val = 3.1234;
label.text = [NSString stringWithFormat: #"XXX %# XXX", [nf stringFromNumber: [NSNumber numberWithDouble: val]]];
I want the label to come out "XXX +3.1 XXX" in the US and the appropriate but equivalent string for any other location. The only things I can find are setPositiveFormat: and setPositivePrefix:.
But I don't want to set the format since I don't know how to format numbers in other countries; I don't know if a plus-sign is used to designate a positive number in Arabic or Russian or some culture I have not thought of. I do know, for example, that decimal points, commas, spaces, etc., all have different meanings in European countries compared to the U.S. - Could the same be true for +/- signs?
What I do currently is:
label.text = [NSString stringWithFormat: #"XXX %s%# XXX", (val < 0) ? "" : "+",
[nf stringFromNumber: [NSNumber numberWithDouble: val]]];
But this presumes that '+' and '-' are correct for all formats.
I'm sure it must be there since it is a standard formatting thing that has been in printf() since the dark ages...
How about this:
NSNumberFormatter *nf = [[NSNumberFormatter alloc] init];
nf.numberStyle = NSNumberFormatterDecimalStyle;
nf.maximumFractionDigits = 1;
double val = 3.1234;
NSString *sign = (val < 0) ? [nf minusSign] : [nf plusSign];
NSString *num = [nf stringFromNumber:#(abs(val))]; // avoid double negative
label.text = [NSString stringWithFormat: #"XXX %#%# XXX", sign, num];
You may need to check to see if num has the sign prefix or not so it isn't shown twice.
Edit: After some playing around, it has been determined, for the "Decimal" style, that no current locale uses a positivePrefix. No current locale uses a plusSign other than the standard + character. No current locale uses a negativePrefix that is different than minusSign. No current locale uses either positiveSuffix or negativeSuffix.
So an easier approach would be to do:
NSNumberFormatter *nf = [[NSNumberFormatter alloc] init];
nf.numberStyle = NSNumberFormatterDecimalStyle;
nf.maximumFractionDigits = 1;
[nf setPositivePrefix:[nf plusSign]];
[nf setNegativePrefix:[nf minusSign]];
label.text = [nf stringFromNumber:#(val)];
This case it's simple, just add the prefix:
nf.positivePrefix= nf.plusSign;
Though it won't use the user's locale, you can do the following to generate the +/- sign without the somewhat expensive overhead of an NSNumberFormatter:
// assume 'number' is an NSNumber
label.text = [NSString stringWithFormat:#"%+.02f", [number floatValue]];
Simple Case:
let f = NumberFormatter()
f.positivePrefix = f.plusSign
Currency Case :
Hack needed, because setting the prefix to plusSign only will remove the currency symbol.
let f = NumberFormatter()
f.numberStyle = .currency
f.positivePrefix = f.plusSign + f.currencySymbol
There is a bit more work depending on the locale.. The currency symbol may be before, or after, but this is probably another subject..
Edit:
Even if it is another subject, I'd say a possible solution to the problem above is to subclass NSNumberFormatter :
override func string(from number: NSNumber) -> String? {
returns ( number.doubleValue >= 0 ? super.plusSign : "" ) + super.string(from: number)
}
This way, NSNumberFormatter should manage the currency position while your subclass simply prepend the + sign. No time to test this in depth, but at least it is an approach.
The underlying formatting language for NSNumberFormatter doesn't have any provision for what you want to do -- it will allow you to specify a localized positive sign on exponents, but not for the entire formatted string. Nor does NSLocale seem to make available the localized positive sign.
Aside from making a dummy string that includes an exponent, pulling the localized positive sign out, and putting your final formatted string together by hand, I think you're out of luck.
A reusable formatter in swift:
var numberFormatter: NSNumberFormatter {
let formatter = NSNumberFormatter()
formatter.numberStyle = .DecimalStyle
formatter.locale = NSLocale(localeIdentifier: "it_IT")//your Locale
formatter.maximumFractionDigits = 2
formatter.minimumFractionDigits = 0
formatter.positivePrefix = formatter.plusSign
return formatter
}
Then use it:
let myDoubleValue = 12.00
let myStringNumber = numberFormatter.stringFromNumber(myDoubleValue)!
I don't think any of the previous answers will actually take into consideration everything you mentioned in your question.
It is true that NumberFormatter does not have an option to set the plus sign visible for all positive numbers when formatting currency values.
Also, replacing prefixes and suffixes will likely break the format for some regions and always replacing a prefix will only work if the set locale uses the currency symbol on the left.
A simple way to address this without losing the locale formatting can be seen below:
var value: Double = 3.1234
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.maximumFractionDigits = 1
if value > 0 {
return formatter.string(for: value.negated())?.replacingOccurrences(
of: formatter.minusSign,
with: formatter.plusSign
)
} else {
return formatter.string(for: value)
}
Even though this can be seen as hack, it's an effective way to achieve everything you mentioned without manually writing a number formatter.
I've got an NSNumberFormatter set up to format using significant digits, so it should only show as many decimal digits as are necessary to correctly display the value.
When it is used to format 7.0 it works exactly as expected and produces #"7", but when it is used to format 0.0 the formatter produces #"0.0" instead of #"0" as would be expected.
NSNumberFormatter *doubleValF = [[NSNumberFormatter alloc] init];
[doubleValF setNumberStyle:NSNumberFormatterDecimalStyle];
[doubleValF setRoundingMode:NSNumberFormatterRoundHalfUp];
doubleValF.maximumFractionDigits = 9;
doubleValF.minimumFractionDigits = 0;
doubleValF.minimumSignificantDigits = 0;
doubleValF.maximumSignificantDigits = 30;
[doubleValF setUsesSignificantDigits:YES];
double value1 = 0.0;
NSString *value1String = [doubleValF stringFromNumber:[NSNumber numberWithDouble:value1]];
double value2 = 7.0;
NSString *value2String = [doubleValF stringFromNumber:[NSNumber numberWithDouble:value2]];
NSLog(#"value1=%#", value1String);
NSLog(#"value2=%#", value2String);
When I run this code, I get the following output:
2012-12-15 15:57:03.425 StackOverflowTests[41701:11303] value1=0.0
2012-12-15 15:57:03.426 StackOverflowTests[41701:11303] value2=7
Following David's LaMacchia's post, just check for a zero value and set the sig fig mode:
if(fabs(value) < 1e-6) {
self.numberLabelFormatter.usesSignificantDigits = NO;
}
else {
self.numberLabelFormatter.usesSignificantDigits = YES;
}
self.numberLabel.text = [self.numberLabelFormatter stringFromNumber:[NSNumber numberWithDouble:value]];
This may not be the correct method, but it works for me.
The issue is related to your having set usesSignificantDigits to YES. I believe the trailing digit, in 0.0, is considered significant.
There's a good discussion of a related issue here: https://stackoverflow.com/a/13110633/1435955
Try to set zeroSymbol property of number formatter to #"0".
doubleValF.zeroSymbol = #"0";
This is my algorithm to find out the speed of my game.
self.speed=.7-self.score/50;
Now how can I make self.speed round to 2 decimal places?
Note: my answer assumes you only care about the number of decimals for the purpose of displaying the value to the user.
When you setup your NSNumberFormatter to format the number into a string for display, setup the formatter with a maximum of two decimal places.
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setNumberStyle:NSNumberFormatterDecimalStyle];
[formatter setMaximumFractionDigits:2];
NSString *formattedNumber = [formatter stringFromNumber:#(self.speed)];
You have the option of using the setRoundingMode: method if you need a specific round method.
BTW - you shouldn't use a string format for this because it doesn't take the user's locale into account to format the number properly.
floats are handled in IEEE754 format, you can't directly decide how many decimal places will be used.You can directly decide how many bits will be used, or indirectly round the las part of the number doing this:
NSString* str=[NSString stringWithFormat: #"%.2f", number];
number= atof([str UTF8String]);
But like maddy pointed, you only need to round/truncate the unwanted decimal digits only when presenting the number to the user, so you could only use the %.2f format specifier when printing it, or use a formatter.
self.speed = (int)(self.speed * 100 + 0.5) / 100.0;
if you want to have that as a string:
NSString *speedString = [NSString stringWithFormat: #"%.2f", self.speed];
I know that there are many different questions about this sort of topic on SO already, but I couldn't find a way to tailor them all to my specific needs.
What I have is a floating point number that gets sent to me through the network that I need to convert and graph out to the screen. The numbers can range from 5.2, 285.159, 294729172.258, -10734.112, etc. What I would like to do is get the value used to round from one digit below the most significant digit.
Example:
5.2 = 5
285.159 = 300
294729172.258 = 300000000
-10734.112 = -11000
Any advice that can be used to help guide me would be greatly appreciated.
Here's my solution:
int roundMostSignificant(float input)
{
NSNumber *number = [NSNumber numberWithFloat:input];
static NSNumberFormatter *formatter = nil;
if (!formatter)
{
formatter = [NSNumberFormatter new];
[formatter setMinimumSignificantDigits:1];
[formatter setMaximumSignificantDigits:1];
[formatter setUsesSignificantDigits:YES];
}
return [[formatter numberFromString:[formatter stringFromNumber:number]] intValue];
}
Yes, this uses objects, but I think that this will be your best bet in the long run, as it handles rounding, parsing, etc. for you.
There is a NSDecimalNumber and NSDecimalNumberHandler classes which does just that. You can define to which precision and to which direction the numbers should be rounded.
Simple example might be:
NSDecimalNumber *dn = [NSDecimalNumber decimalNumberWithMatnissa:294729172258 exponent:-3 isNegative:NO];
NSDecimalNumberHandler *dnh = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundPlain scale:-6 raiseOnExactness:NO raiseOnOverflow:NO raiseOnUnderflow:NO raiseOnDivideByZero:YES];
NSDecimalNumber *rounded = [dn decimalNumberByRoundingAccordingToBehavior:dnh];
This would probably work for your biggest number.