Rounding issue when using NSString and %f [duplicate] - objective-c

I have a floating point number that have more decimal digits, for example:
float fRes = 10.0 / 3.0;
actually the fRes value is 3.3333333333333
it's possible set for example 2 decimal digits:
float fRes = 10.0 / 3.0;
// fRes is 3.333333333333333333333333
float fResOk = FuncRound( fRes, 2 );
// fResOk is 3.33
thanks in advance

I don't know where you are using this rounded number, but you should only round your value when displaying it to the user, there are C based format string ways to round floating point numbers for example
[NSString stringWithFormat:#"%.2f", value];
as you may have already read, floating point number are approximations of real numbers, so doing fResOk = roundf( fRes*100.0)/100.0; may not give you 3.33 but a number which is just as close as you can get with floating point number to 3.33.

Assuming that you're looking for the correct function to round to a certain number of digits, you'll probably find it easiest to do the following:
fResOk = roundf( fRes*100.0)/100.0;
That will multiply the value by 100 (giving you your 2 digits of significance), round the value, and then reduce it back to the magnitude you originally started with.

Related

how to set precision in Objective-C

In C++, there is a std::setprecision function can set float/double precision.
how can i set precision in Objective-C? and this print below:
(lldb) p 10/200
(int) $0 = 0
(lldb) p (float)10/200
(float) $1 = 0.0500000007
line 3 result is 0.0500000007, why is '7' in the result? how can i get the result is 0.05?
Floating-point numbers are binary floating-point numbers. 0.05 cannot be represented exactly by a binary floating point number. The result cannot ever be exactly 0.05.
In addition, you are quite pointlessly using float instead of double. float has only six or seven digits precision. Unless you have a very good reason that you can explain, use double, which gives you about 15 digits of precision. You still won't be able to get 0.05 exactly, but the error will be much less.
You may use NSNumberFormatter to format objects in a wide variety of ways --- too numerous to list here, see the documentation available from Xcode. Also see the Data Formatting Guide.
You must make change between % modulo operator and its identifier f in order to get desired result.
NSString* formattedNumber = [NSString stringWithFormat:#"%.02f", myFloat];
%.02f tells the formatter that you will be formatting a float (%f) and, that should be rounded to two places, and should be padded with 0s.
Example:
%f = 25.000000 // results 25.000000
%.f = 25 // results 25
%.02f = 25.00 // results 25.00
plz use
double A = 0.0500000007;
NSString *b =[NSString stringWithFormat:#"$%.02f",A] ;
double B = [b doubleValue];

In objective c from a float number I want to sepatate the decimals to do further math work on

I am setting up a calculator that will generate a float number after the user's input. As an example: if the answer generated is 1.75 that would actually represents 1.75 hours. I want to split the answer into two parts to read 1 hr. 45 min which will be more user friendly than .75 of an hour is.
So I need to be able to delete the whole digit(s) (in this example the "1") before the decimal to get a variable value using the .75 --kind of like this:
mIn = (.75 * 60) which would give me the 45 minutes value to put in my...
[NSString stringWithFormat:#"#% hr. #% min", hRs, mIn]; type of statement
Any help on this would be greatly appreciated.
You almost certainly do not want to use a float to store a user-entered number, particularly for a calculator. This will lead to decimal/binary rounding errors that will drive you crazy. You want to use NSDecimalNumber for this kind of work.
The other answers here will work, but you want to replace floor() with decimalNumberByRoundingAccordingToBehavior:. You'll use an NSDecimalNumberHandler with a rounding mode of NSRoundDown and an appropriate scale (probably 2 or 3 for your purposes).
Use floor(floatValue) to get the integer portion, subtract that from the floatValue to get the decimal portion.
Ex:
float floatValue = 1.75;
float integerPortion = floor(floatValue);
float decimalPortion = floatValue - integerPortion;
NSString *timeString = [NSString stringWithFormat:#"%.0f hr. %.0f min", integerPortion, decimalPortion * 60];
NSLog(#"timeString: %#", timeString);
NSLog output:
timeString: 1 hr. 45 min
You can cast the floating value to an int and subtract that from the value or you can floor it.
float time = 1.75;
int minutes = (time - (int)time) * 60; //or (time - floor(time)) * 60;
NSLog(#"Time: %#", [NSString stringWithFormat:#"%d hr. %d min", (int)time, minutes]);

iOS round a float

I have a floating point number that have more decimal digits, for example:
float fRes = 10.0 / 3.0;
actually the fRes value is 3.3333333333333
it's possible set for example 2 decimal digits:
float fRes = 10.0 / 3.0;
// fRes is 3.333333333333333333333333
float fResOk = FuncRound( fRes, 2 );
// fResOk is 3.33
thanks in advance
I don't know where you are using this rounded number, but you should only round your value when displaying it to the user, there are C based format string ways to round floating point numbers for example
[NSString stringWithFormat:#"%.2f", value];
as you may have already read, floating point number are approximations of real numbers, so doing fResOk = roundf( fRes*100.0)/100.0; may not give you 3.33 but a number which is just as close as you can get with floating point number to 3.33.
Assuming that you're looking for the correct function to round to a certain number of digits, you'll probably find it easiest to do the following:
fResOk = roundf( fRes*100.0)/100.0;
That will multiply the value by 100 (giving you your 2 digits of significance), round the value, and then reduce it back to the magnitude you originally started with.

Objective-C: Strange calculation result

I am learning Objective-C and have completed a simple program and got an unexpected result. This program is just a multiplication table test... User inputs the number of iterations(test questions), then inputs answers. That after program displays the number of right and wrong answers, percentage and accepted/failed result.
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSLog(#"Welcome to multiplication table test");
int rightAnswers; //the sum of the right answers
int wrongAnswers; //the sum of wrong answers
int combinations; //the number of combinations#
NSLog(#"Please, input the number of test combinations");
scanf("%d",&combinations);
for(int i=0; i<combinations; ++i)
{
int firstInt=rand()%8+1;
int secondInt=rand()%8+1;
int result=firstInt*secondInt;
int answer;
NSLog(#"%d*%d=",firstInt,secondInt);
scanf("%d",&answer);
if(answer==result)
{
NSLog(#"Ok");
rightAnswers++;
}
else
{
NSLog(#"Error");
wrongAnswers++;
}
}
int percent=(100/combinations)*rightAnswers;
NSLog(#"Combinations passed: %d",combinations);
NSLog(#"Answered right: %d times",rightAnswers);
NSLog(#"Answered wrong: %d times",wrongAnswers);
NSLog(#"Completed %d percent",percent);
if(percent>=70)NSLog(#"accepted");
else
NSLog(#"failed");
[pool drain];
return 0;
}
Problem (strange result)
When I input 3 iterations and answer 'em right, i am not getting of 100% right. Getting only
99%. The same count I tried on my iPhone calculator.
100 / 3 = 33.3333333... percentage for one right answer (program displays 33%. The digits after mantissa getting cut off)
33.3333333... * 3=100%
Can someone explain me where I went wrong? Thanx.
This is a result of integer division. When you perform division between two integer types, the result is automatically rounded towards 0 to form an integer. So, integer division of (100 / 3) gives a result of 33, not 33.33.... When you multiply that by 3, you get 99. To fix this, you can force floating point division by changing 100 to 100.0. The .0 tells the compiler that it should use a floating point type instead of an integer, forcing floating point division. As a result, rounding will not occur after the division. However, 33.33... cannot be represented exactly by binary numbers. Because of this, you may still see incorrect results at times. Since you store the result as an integer, rounding down will still occur after the multiplication, which will make it more obvious. If you want to use an integer type, you should use the round function on the result:
int percent = round((100.0 / combinations) * rightAnswers);
This will cause the number to be rounded to the closest integer before converting it to an integer type. Alternately, you could use a floating point storage type and specify a certain number of decimal places to display:
float percent = (100.0 / combinations) * rightAnswers;
NSLog(#"Completed %.1f percent",percent); // Display result with 1 decimal place
Finally, since floating point math will still cause rounding for numbers that can't be represented in binary, I would suggest multiplying by rightAnswers before dividing by combinations. This will increase the chances that the result is representable. For example, 100/3=33.33... is not representable and will be rounded. If you multiply by 3 first, you get 300/3=100, which is representable and will not be rounded.
Ints are integers. They can't represent an arbitrary real number like 1/3. Even floating-point numbers, which can represent reals, won't have enough precision to represent an infinitely repeating decimal like 100/3. You'll either need to use an arbitrary-precision library, use a library that includes rationals as a data type, or just store as much precision as you need and round from there (e.g. make your integer unit hundredths-of-a-percent instead of a single percentage point).
You might want to implement some sort of rounding because 33.333....*3 = 99.99999%. 3/10 is an infinite decimal therefore you need some sort of rounding to occur (maybe at the 3rd decimal place) so that the answer comes out correct. I would say if (num*1000 % 10 >= 5) num += .01 or something along those lines multiply by 100 moves decimal 3 times and then mod returns the 3rd digit (could be zero). You also might only want to round at the end once you sum everything up to avoid errors.
EDIT: Didn't realize you were using integers numbers at the end threw me off, you might want to use double or float (floats are slightly inaccurate past 2 or 3 digits which is OK with what you want).
100/3 is 33. Integer mathematics here.

NSTimeInterval to readable NSNumber

NSTimeInterval == double; (e.g. 169.12345666663)
How can I round up this double so that there are only 2 digits left after the "dot"?
It would be very good if the result is a NSNumber.
If this is for display purposes, take a look at NSNumberFormatter.
If you really want to round the double in your calculations for some reason, you can use the standard C round() function.
A NSDecimal can be rounded to a specified number of digits with NSDecimalRound().
double d = [[NSDate date] timeIntervalSince1970];
NSDecimal in = [[NSNumber numberWithDouble:d] decimalValue];
NSDecimal out;
NSDecimalRound( &out, &in, 2, NSRoundUp );
NSDecimalNumber *result = [NSDecimalNumber decimalNumberWithDecimal:out];
If you really want two digits left after the dot, multiply by 100, round it using round() function, divide it by 100 again. However, this will not guarantee that it really has only two digits after the dot, since by dividing it again, you may get a number that cannot really be expressed with floating point notation and when you expect 0.1 you may in fact get 0.09999..., that's because you cannot really express 0.1 using floating point notation.
If you just want to round it to two digits after the dot for display purposes, you can use NSNumberFormatter as has been suggested or just use:
printf("%.2f\n", yourTimeInterval);
NSLog(#"%.2f\n", yourTimeInterval);
or to get an NSString, you can also use the following, which is probably even faster than using a NumberFormatter (however, it won't be localized according to the user prefs):
NSString * intervalStr = nil;
char * intervalStrTmp = NULL;
asprintf(&intervalStrTmp, "%.2f", yourTimeInteval);
if (intervalStrTmp) {
intervalStr = [[NSString alloc] initWithUTF8String:intervalStrTmp];
free(intervalStrTmp);
}
In the vast majority of cases rounding a number is something you should only do at display time. The properties of floating-point numbers (double or not) make it impossible to store certain numbers at a fixed-precision.
For information about formatting a number so it displays to two decimal places, see this other post.
Does this HumanReadableTimeInterval help? It returns a NSString, though.
Alternatively, you can round yourself by multiplying with 100, converting to an integer and dividing through 100 again.
I would just use the ANSI C round() function.
You can always round the number using:
double round2dec(double a) { return round(a * 100) / 100; }
But chances are that the representation of the result as a double will not have only 2 decimals.
Now, if by using the == sign, you meant that the comparison of your two double numbers is made only to the second decimal. Here is what you can do:
fabs(round2dec(NSTimeInterval) - round2dec(double)) < std::numeric_limits<double>::epsilon()