Having a hard time working with floats - objective-c

I wasn't really sure what to name the title.
I'm checking to see if the value of two floats are the same. If I use printf() or NSLog(), the values return 0.750000. However, a line like if (value1 == value2) { return TRUE; } doesn't work. I can assume that in reality, the floats are beyond the 7 decimal places, and printf() / NSLog() can't return a value beyond 7 decimals.
I tried googling a way to see how I could cut down a float to a smaller amount of decimal places, or simply convert it to another data type, but I didn't get such luck so far.

You might want to peek at float.h (http://www.gnu.org/software/libc/manual/html_node/Floating-Point-Parameters.html) for a non-arbitrary definition of epsilon. In particular, FLT_EPSILON and FLT_DIG.

You can decide of an epsilon that is the maximum value under which number are equals. Like
#define EPSILON 0.0001
if (fabs(floatA - floatB) < EPSILON) { retun TRUE; }
fabs(x) returns the absolute value of the double x.
You may also want to use the double instead of float data type (double is twice the size of a float).

When ever you compare floating point numbers you need to use a tolerance:
if (Abs(value1 - value2) < epsilon)
{
}
where epsilon is a value such as 0.000001

Related

Remove zeros from CGFloat

I have a CGFloat which I am trying to round to 1 decimal place. Using the below code, the CGFloat is rounded to 3.700000, according to NSLog:
averageRating = floorf(averageRating * 10.0f + 0.5) / 10.0f;
However, for my code to work, which depends on if statements such as:
if (averageRating == 0.1f)
I need to remove the zeros. I would like the CGFloat to always be to 1 decimal place, as I will always round it to 1 d.p. using the floorf code above.
So again: How can I remove the extra zeros from the CGFloat? All help appreciated.
The == operator will return 100% reliably whether two floating-point numbers are equal or not. HOWEVER two calculations that you think should give the same result will not necessarily give the same result, so unless you know exactly what you are doing, and what your compiler is doing, comparing a floating-point number against 0.1f is a very dangerous thing to do. (And obviously you don't know what you are doing, or you wouldn't be asking).
The solution is very simple:
double average_times_ten = round (averageRating * 10.0);
if (average_times_ten == 1.0) { ... }
And don't use float unless you have a very good reason to do so, which you can explain when asked about it. Use double.

Converting int to double screws up the decimal point

In the debug window, when I input this command:
po 1912/10.0
The output is 191.19999999999999.
What I really want to get back is 191.2.
Why is this happening, and how can I convert an int into a double with precision?
From What Every Programmer Should Know About Floating-Point Arithmetic:
Why don’t my numbers, like 0.1 + 0.2 add up to a nice round 0.3, and instead I get a weird result like 0.30000000000000004?
Because internally, computers use a format (binary floating-point) that cannot accurately represent a number like 0.1, 0.2 or 0.3 at all.
When the code is compiled or interpreted, your “0.1” is already rounded to the nearest number in that format, which results in a small rounding error even before the calculation happens.
This is why programmers say you should only ever store money as an integer. For example int cents = 1995; rather than float dollars = 19.95.
If your app doesn't need to be 100% precise (for example, if you're calculating screen coordinates or translucency or a color) just format your float rounded to 1 or 2 decimal places:
double someValue = 1912/10.0;
NSLog(#"2 decimals: %.2f", someValue);
NSLog(#"0 decimals: %.0f", someValue);
This code will output:
2 decimals: 191.20
0 decimals: 191
That's normal for a floating point number. Double is obviously just an extended precision floating point number. If you want to keep the pristine decimal digits, then don't allow any float/double conversion. Instead store the result as a scaled integer (in your case 1912) and place the decimal manually.
Let me try to explain this another way. When you express a number with a fractional part with a float or double, precision is most often lost. There's no way around that. If you store 1912 as a float and store 10 as a float then divide the first stored value by the second, the value will NEVER be 191.2. That's just the way floating point numbers work. If you look at the number in a debugger you'll see something like 191.19999999999999 as you describe. This, in itself, is an approximation as the value should be 191.19999999999999... but of course you can't even type all the digits in the decimal value of that stored result as the number of digits approaches infinity.
If you're going to use floating point, that's what you'll get. No way around it.
If you really want to get 191.2, then you can't use floating point, at least without doing rounding. Instead, you need to normalize the numbers by just storing the value as 1912 and printing the value with a decimal point to the left of the 2.
There's another brief online description at http://floating-point-gui.de/basic/

Objective C, division between floats not giving an exact answer

Right now I have a line of code like this:
float x = (([self.machine micSensitivity] - 0.0075f) / 0.00025f);
Where [self.machine micSensitivity] is a float containing the value 0.010000
So,
0.01 - 0.0075 = 0.0025
0.0025 / 0.00025 = 10.0
But in this case, it keeps returning 9.999999
I'm assuming there's some kind of rounding error but I can't seem to find a clean way of fixing it. micSensitivity is incremented/decremented by 0.00025 and that formula is meant to return a clean integer value for the user to reference so I'd rather get the programming right than just adding 0.000000000001.
Thanks.
that formula is meant to return a clean integer value for the user to reference
If that is really important to you, then why do you not multiply all the numbers in this story by 10000, coerce to int, and do integer arithmetic?
Or, if you know that the answer is arbitrarily close to an integer, round to that integer and present it.
Floating-point arithmetic is binary, not decimal. It will almost always give rounding errors. You need to take that into account. "float" has about six digit precision. "double" has about 15 digits precision. You throw away nine digits precision for no reason.
Now think: What do you want to display? What do you want to display if the result of your calculation is 9.999999999? What would you want to display if the result is 9.538105712?
None of the numbers in your question, except 10.0, can be exactly represented in a float or a double on iOS. If you want to do float math with those numbers, you will have rounding errors.
You can round your result to the nearest integer easily enough:
float x = rintf((self.machine.micSensitivity - 0.0075f) / 0.00025f);
Or you can just multiply all your numbers, including the allowed values of micSensitivity, by 4000 (which is 1/0.00025), and thus work entirely with integers.
Or you can change the allowed values of micSensitivity so that its increment is a fraction whose denominator is a power of 2. For example, if you use an increment of 0.000244140625 (which is 2-12), and change 0.0075 to 0.00732421875 (which is 30 * 2-12), you should get exact results, as long as your micSensitivity is within the range ±4096 (since 4096 is 212 and a float has 24 bits of significand).
The code you have posted is correct and functioning properly. This is a known side effect of using floating point arithmetic. See the wiki on floating point accuracy problems for a dull explanation as to why.
There are several ways to work around the problem depending on what you need to use the number for.
If you need to compare two floats, then most everything works OK: less than and greater than do what you would expect. The only trouble is testing if two floats are equal.
// If x and y are within a very small number from each other then they are equal.
if (fabs(x - y) < verySmallNumber) { // verySmallNumber is usually called epsilon.
// x and y are equal (or at least close enough)
}
If you want to print a float, then you can specify a precision to round to.
// Get a string of the x rounded to five digits of precision.
NSString *xAsAString = [NSString stringWithFormat:#"%.5f", x];
9.999999 is equal 10. there is prove:
9.999999 = x then 10x = 99.999999 then 10x-x = 9x = 90 then x = 10

Objective C float is not showing all decimals

I'm passing a float to a method but it's not showing all decimals. I have no idea why this is happening.
Here's an example:
[[LocationApiCliente sharedInstance] nearPlacesUsingLatitude:-58.3645248331830402 andLongitude:-34.6030467894227982];
Then:
- (BOOL)nearPlacesUsingLatitude:(double)latitude andLongitude:(double) longitude {
NSString *urlWithCoords = [NSString stringWithFormat:#"%#&lat=%f&long=%f", CountriesPath, latitude, longitude];
Printing urlWithCoords will result in:
format=json&lat=-58.364525&long=-34.603047
More of this. What I'm getting from the output terminal:
(lldb) p -3.13419834918349f
(float) $4 = -3.1342
(lldb) p -3.13419834918349
(double) $5 = -3.1342
Any ideas?
Change the %fs in your formatting strings to specify the desired number of decimals, e.g., %.16f.
Note that the number of decimals shown does not guarantee that they are correct, but at least they won't be truncated.
Overall the problem is that floating point numbers do not contain information about the precision, and cannot precisely represent some decimal values, so formatting can not in the general case “autodetect” the number of decimals. So you just need to override the default by specifying the desired number and accept that it's not representative of location accuracy. But since you seem to be passing the floats to another program via the URL, this shouldn't be a problem—a larger number of decimals is better.
It looks like CoreLocation uses doubles to represent degrees, so I'd be surprised if there's any more geographic precision to be found on the device.
But, in general, if you want to represent higher precision than double, you can use long double in Objective-C like this...
long double myPi = 3.141592653589793;
NSLog(#"%16.16Lf", myPi);

Objective-C - Get number of decimals of a double variable

Is there a nice way to get the number of decimals of a double variable in Objective-C?
I am struggling for a while to find a way but with no success.
For example 231.44232000 should return 5.
Thanks in advance.
You could, in a loop, multiply by 10 until the fractional part (returned by modf()) is really close to zero. The number of iterations'll be the answer you're after. Something like:
int countDigits(double num) {
int rv = 0;
const double insignificantDigit = 8;
double intpart, fracpart;
fracpart = modf(num, &intpart);
while ((fabs(fracpart) > 0.000000001f) && (rv < insignificantDigit)) {
num *= 10;
rv++;
fracpart = modf(num, &intpart);
}
return rv;
}
Is there a nice way to get the number of decimals of a double variable in Objective-C?
No. For starters, a double stores a number in binary, so there may not even be an exact binary representation that corresponds to your decimal number. There's also no consideration for the number of significant decimal digits -- if that's important, you'll need to track it separately.
You might want to look into using NSDecimalNumber if you need to store an exact representation of a decimal number. You could create your own subclass and add the ability to store and track significant digits.