Floating in Uncertainty


Among the primitive data types that Objective-C offers are float and double. Similar to long, double is simply double the storage in bits of float. However, as the name suggests, both are floating-point numbers. That is, the decimal point literally “floats” around as necessary. This can lead to many subtle bugs, even between executions of the same program.

How Do They Work?

Both types have a certain numbers of bits for storage. The exact number of bits varies per implementation, just as the exact storage sizes for ints and doubles aren’t fixed. However, a floating point number effectively has two parts, the “whole” part and the “fractional” part. The floating nature comes in because the number of bits used to store each section is not always the same, and will vary depending on the sizes of the numbers involved.

The Precise Issue

Although there are an infinite number of integers, they all differ by the same amount—1. Therefore it is relatively easy to represent an integer value as bits. By contrast, however, the difference between one decimal number and another is incredibly small, and, what’s worse, this difference can change. When trying to squeeze an infinite number of digits with infinite precision into a finite number of bits, something has to give. This usually means that the floating-point value is rounded, and is not completely accurate. Here’s a simple program (using plain C) to illustrate this issue:

int main (int argc, const char *argv[]) {
	float f = 1234.123456789;
	printf("%f\n", f);
	printf("%.9f\n", f);
	return 0;
}

Output:

1234.123413
1234.123413086

The first print statement (printf() is nearly identical to NSLog(), except that it takes C-style strings instead) shows the actual value of f in memory, with ten digits in this case. Notice that the value is different from the value we assigned to the variable. This is because there are not enough bits to hold every single digit, so some of it had to be rounded away. That rounding is not perfectly accurate—it rounds the tailing ‘456789’ into ‘413’. If, however, we try to force it to display nine digits as seen in the next line, we still end up with the ‘413’, along with a tailing ‘086’—not digits that we put in.

Comparisons

How many times should this loop run?

#import <Foundation/Foundation.h>
int main (int argc, const char * argv[]){
	NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
	int count = 0;
	for (float i = 10; i != 0; i -= 0.1) {
		count++;
		printf("count is %d\n", count);
	}
	[pool drain];
    return 0;
}

Common sense tells us that it should run 100 times, but in fact this is an infinite loop. Because of these rounding errors, i will never be exactly equal to zero. It’ll come close after 100 cycles through, but it won’t be perfect. As such, when dealing with floating point numbers, you want to check to see if it’s close to a value. In the above example, the comparison should be i >= 0; (the equal bit because the floating point number might be a tiny negative value) to ensure that the loop ends.

To check if two floating point numbers are equal, you could use the == (double equals) operator, but there’s no guarantee that they will give an accurate result, especially after many calculations. A better way (albeit less efficient) would be to get the absolute value of their difference, and see if it’s less than a small number, such as 0.00001. If it’s less, you can safely assume they’re equal; otherwise, they’re not.

Floating point inaccuracies can be very difficult to debug, so it pays off to take precautions earlier. As a matter of fact, I spent about half an hour trying to figure out why something wasn’t showing up on screen, when in fact a botched conversion from integers to floating point (similar issues result) lead to everything being 0. Not fun.

Extension 2: Floating-Point Operations


Not all numbers are integers. Therefore, Objective-C lets you define floating-point values—numbers with a fractional portion. There are two basic types—float and double.

Floating-point values do not follow the rules of integer division—that is, dividing by floating-point values produces floating-point results.

Type float

In certain programming languages (Java comes to mind) the float type is almost never used. In Objective-C, it is the more commonly used of the two—both for practical and memory reasons.

A floating point number must contain a decimal portion, but you can omit digits before or after the decimal point—obviously, not both. The entire number ca be prefixed by a negative sign. Therefore, 3., 1.8, .295, and -.59 are all valid floating point numbers. To display floats in an NSLog call, use %f.

Scientific Notation

As you may recall from a high-school math class, scientific notation is a method of writing absurdly large or small numbers. It takes the form 5.925×102, where the general notation is of a floating-point value followed by a multiplication, a number (generally a power of 10), and an exponent. This number is written in code with the form 5.925e4. The e, formally known as the mantissa, can be written as a capital or lowercase. The mantissa can be either positive or negative; a negative value, such as 2.25e-3, would correspond to a value of 2.25×10-3, or 0.00225.

To display scientific notation, use %e. Alternatively, you can use %g to have NSLog decide whether to display the usual value or the scientific notation—if the exponent is less than -4 or greater than 5, the scientific notation is used; otherwise, the standard floating point notation is used.

Type double

A double value is a more precise float value—the former stores twice as many digits, and on most systems it uses 64 bits.

Like Java, all floating point constants in Objective-C are double. To force a float, append either f or F to the end of the floating point value. Unlike Java, however, floats are used as a general data type for floating-point variables, due to the fact that they require less memory. The distinction is that of constants versus that of variables.

The same format specifiers apply to doubles, as well as scientific notation.

  • Welcome

    My goal is to make CupsOfCocoa into a beautiful source for beginners to the iPhone platform to get started. Subscribe below for more, and stay tuned!

  • Contact Me

    If you need to contact me for any reason, feel free to send me an email.
  • The Giving Spirit

    If you've found this site helpful, would you consider donating a little sum? Any amount is appreciated...Thanks so much!

  • Roadmap

  • Enter your email address to follow this blog and receive notifications of new posts by email.

    Join 220 other followers

  • Back to the Past

    May 2020
    S M T W T F S
     12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31  
  • Time Machine

  • You count!

    • 622,650 views
  • Worldwide Stats

    free counters
%d bloggers like this: