NSNumberFormatter question - iphone

I'm trying to save a float like so
[NSNumber numberWithFloat:[dosage floatValue]];
and read the value like so:
dosage = [NSString stringWithFormat:#"%1.0f", [prop.dosage floatValue]];
The Problem is that numbers like 0.11 end up being 0
I've read that I can use NSNumberFormatter, but the docs are not very clear on how to set it for rounding.

if its already a string then y do you need to implement stringWithFormat?
for 2 digits floatvalue use %.2f
i.e.
dosage = [NSString stringWithFormat:#"%0.2f", [prop.dosage floatValue]];
HAPPY iCODING...

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];
}

NSNumberFormatter to show a maximum of 3 digits

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.

iphone NSString stringWithFormat and float

I have an input with UIKeyboardTypeDecimalPad and I need my user to input a float (with unlimited characters after a dot). After the input I filter the string with :
NSString *newValue = [NSString stringWithFormat:#"%.f",[textField.text floatValue]]
But that gives me a lot of unnecessary digits after a dot (for example for 2.25 it gives 2.249999).
All I need is to filter the input so it'll be a legal float (digits and not more than one dot).
How do I do that?
NSString *newValue = [NSString stringWithFormat:#"%0.1f", [textField.text floatValue]];
the number after the dot is the number of decimal places you want.
UPDATE:
You could use string manipulation to determine the number of decimal places the user typed in (don't forget to check for edge cases):
NSInteger numberOfDecimalPlaces = textString.length - [textString rangeOfString:#"."].location - 1;
and then if you want to create a new string with a new float to the same level of display precision you could use:
NSString *stringFormat = [NSString stringWithFormat:#"%%0.%if", numberOfDecimalPlaces];
NSString *newString = [NSString stringWithFormat:stringFormat, newFloat];
Not sure if this is what you want but try something like the following:
NSNumberFormatter *nf = [[NSNumberFormatter alloc] init];
// set to long number of decimals to accommodate whatever a user might enter
[nf setMaximumFractionDigits:20];
NSString *s = [nf stringFromNumber:
[NSNumber numberWithDouble:[userEnteredNumberString doubleValue]]
];
NSLog(#"final:%#",s);
Try using a double instead of float. I think the double removes all trailing zero's.

so "lame" - how to have from float = 0.39824702 just float = 0.398?

..so only 3 digit numbers afer "."..
float a = 0.9876543
I would like to have 0.987 only in memory because of transmitting the number over bluetooth..
I'm using iphone SDK..
thank you... :)
A single precision float takes up the same amount of storage whether you're storing an "easy" number like 1.0 or a "complicated" number like 1.23456789. (Likewise for double precision floats -- they're all the same size as each other, although obviously they take more storage space than single precision floats.)
Any network protocol/transport such a Bluetooth involves overheads in just making the thing work, such as headers etc. These overheads mean that the amount of storage you're wanting to save probably just isn't worth the bother - you're talking about shaving a few bytes off a communication which probably a good few multiples bigger than your potential saving anyway.
A more realistic optimization might be to collect some readings and then transmit them all at once, e.g. 32 at once. That makes your "real information" to "protocol overhead" ratio higher.
Here's some advice about optimization you should be aware of:
http://c2.com/cgi/wiki?PrematureOptimization
Don't optimize too early!
You have three answers :
the apple way :
float a = 0.9876543;
NSNumber *number = [NSNumber numberWithFloat: a];
NSNumberFormatter *formatter = [NSNumberFormatter new];
[formatter setMaximumFractionDigits:3];
NSLog(#"%#", [formatter stringFromNumber: number]);
[formatter release], formatter = nil;
the Nerd C way :
float a = 0.9876543;
a = roundf(a*1000)*.001f; // or floatf() if you want truncate and not round number
the apple trick :
float a = 0.9876543;
NSString* tmp = [NSString stringWithFormat:#"%.3f",a];
a = [tmp floatValue];
Good luck
Are you trying to print the number? Anyway, I'm not sure if this is what you're looking for:
float a = 0.9876543;
NSNumber *number = [NSNumber numberWithFloat: a];
NSNumberFormatter *formatter = [NSNumberFormatter new];
[formatter setMaximumFractionDigits:3];
NSLog(#"%#", [formatter stringFromNumber: number]);

intValue is missing decimals

I have a price that I need to convert based on the selected currency.
NSString *path = [[NSBundle mainBundle] bundlePath];
NSString *finalPath = [path stringByAppendingPathComponent:#"currency.plist"];
NSDictionary *plistDictionary = [[NSDictionary dictionaryWithContentsOfFile:finalPath] retain];
int price = [price intValue];
int currencyValue = [[plistDictionary valueForKey:#"EUR"] intValue];
int convertedCurrency = (price / currencyValue);
price is an NSNumber and the valueForKey is also a number from a plist file I have setup with conversion rates.
The problem I am having, is that my price is missing the decimals. Everytime I get the intValue from the price it's just rounded up or down. The same issue exists for the exchange rate I get from the plist.
I have looked into NSNumberFormatter but it won't let me setFormat for the NSNumberFormatter. Any advice, please?
int is an integer type - by definition it does not have a decimal value. Instead try:
float fprice = [price floatValue];
float currencyValue = [[plistDictionary valueForKey:#"EUR"] floatValue];
float convertedCurrency = (fprice / currencyValue);
intValue returns an integer, which (by definition) is rounded to a number without decimals.
You could use doubleValue, which returns a double (which does have the fractional portion) or decimalValue which returns a NSDecimal object.
Take the price string and remove the period. After that convert the NSString to and int, which means you end up with 4235 pennies (or 42 dollars and 35 cents). (Also, make sure that the price string you're getting has two decimal places! Some people are lazy, and output "3.3" for "$3.30".)
NSString *removePeriod = [price stringByReplacingOccurrencesOfString:#"." withString:#""];
int convertedPrice = [removePeriod intValue];
float exchangeRate;
Then get the exchange rates depending on which currency has been selected and use the following code:
int convertedCurrency = round((double)convertedPrice / exchangeRate);
addCurrency = [NSString stringWithFormat: #"%0d.%02d", (convertedCurrency / 100), (convertedCurrency % 100)];
addCurrency is your final price.
To deal with the exact number of deciamlas and if all your currencies have 2 decimal places (e.g not JPY) make all numbers the number of cents
e.g. store 43.35 EUR as 4235.
Then you can use in arithmetic and then just deal with formatting using value/100.0 and NSNumberFormatter