Basic Data Types and Calculations - Try It Out: Floating-Point Arithmetic (
Page 10 of 14 )
Suppose that you want to construct a circular pond in which you want to keep a number of fish. Having looked into the matter, you know that you must allow 2 square feet of surface area on the pond for every 6 inches of fish length. You need to figure out the diameter of the pond that will keep the fish happy. Here’s how you can do it:
// Program 2.6 Sizing a pond for happy fis
h #include
#include
// For square root calculation using std::cout; using std::cin; using std::sqrt;
int main() { const double fish_factor = 2.0/0.5; // Area per unit length of fish const double inches_per_foot = 12.0; const double pi = 3.14159265;
double fish_count = 0.0; // Number of fish double fish_length = 0.0; // Average length of fish
cout << "Enter the number of fish you want to keep: "; cin >> fish_count; cout << "Enter the average fish length in inches: "; cin >> fish_length; fish_length = fish_length/inches_per_foot; // Convert to feet
// Calculate the required surface area double pond_area = fish_count * fish_length * fish_factor;
// Calculate the pond diameter from the area double pond_diameter = 2.0 * sqrt(pond_area/pi);
cout << "nPond diameter required for " << fish_count << " fish is " << pond_diameter << " feet.n"; return 0; }
(Continued)
With input values of 20 fish with an average length of 9 inches, this example produces the following output:
Enter the number of fish you want to keep: 20 Enter the average fish length in inches: 9 Pond diameter required for 20 fish is 8.74039 feet.
You first declare three
const
variables that you’ll use in the calculation:
const double fish_factor = 2.0/0.5; // Area per unit length of fish const double inches_per_foot = 12.0; const double pi = 3.14159265;
Notice the use of a constant expression to specify the value for
fish_factor
. You can use any expression that produces a result of the appropriate type to define an initializing value for a variable. You have declared
fish_factor
,
inches_per_foot
, and
pi
as
const
because you don’t want to allow them to be altered.
Next, you declare variables in which you’ll store the user input:
double fish_count = 0.0; // Number of fish double fish_length = 0.0; // Average length of fish
You don’t have to initialize these, but it’s good practice to do so.
Because the input for the fish length is in inches, you need to convert it to feet before you use it in the calculation for the pond:
fish_length = fish_length/inches_per_foot; // Convert to feet
This stores the converted value back in the original variable.
You get the required area for the pond with the following statement:
double pond_area = fish_count * fish_length * fish_factor;
The product of
fish_count
and
fish_length
gives the total length of all the fish, and multiplying this by
fish_factor
gives the required area.
The area of any circle is given by the formula p r2, where r is the radius. You can therefore calculate the radius of the pond as the square root of the area divided by p. The diameter is then twice the radius, and the whole calculation is carried out by this statement:
pond_diameter = 2.0 * sqrt(pond_area / pi);
74 You obtain the square root using a function that’s declared in the standard header
. The
sqrt()
function returns the square root of the value of the expres
sion placed between the parentheses after the function name. In this case, the value returned is of type
double
because the value of the expression is of type
double
, but there’s also a version that returns the square root of a
float
value as type
float
. The
header contains declarations for many other standard library numerical functions, as you’ll see a little later in this chapter. You’ll look into functions in detail, including how you can define your own functions, in Chapter 8. Of course, like almost all the other names in the standard library,
sqrt
is defined within the
std
namespace, so you have a
using
declaration for the name at the beginning of your program file.
The last step before exiting
main()
is to output the result:
cout << "nPond diameter required for " << fish_count << " fish is
" << pond_diameter << " feet.n";
This outputs the pond diameter required for the number of fish specified. Working with Floating-Point Values
For most computations using floating-point values, you’ll find that type
double
is more than adequate. However, you need to be aware of the limitations and pitfalls of work
ing with floating-point variables. If you’re not careful, your results may be inaccurate, or even incorrect. The following are common sources of errors when using floating-point values:
- Many decimal values don’t convert exactly to binary floating-point values. The small errors that occur can easily be amplified in your calculations to produce large errors.
- Taking the difference between two nearly identical values can lose precision. If you take the difference between two values of type
float
that differ in the sixth significant digit, you’ll produce a result that may have only one or two digits of accuracy. The other significant digits that are stored may represent errors.
- Dealing with a wide range of possible values can lead to errors. You can create an elementary illustration of this by adding two values stored as type
float
with 7 digits of precision but in which one value is 108 times larger that the other. You can add the smaller value to the larger as many times as you like, and the larger value will be unchanged. The
header defines constants for the floating-point types that are the smallest values that you can add to 1.0 and get a different result. The constants are
FLT_EPSILON
,
DBL_EPSILON
, and
LDBL_EPSILON
.
Let’s see how these errors can manifest themselves in practice, albeit in a somewhat artificial situation.
Try It Out: Errors in Floating-Point Calculations
Here’s an example contrived to illustrate how the first two points can combine to produce errors:
// Program 2.7 Floating point errors
| #include
|
| using std::cout; |
| using std::endl; |
| int main() { |
| float value1 = 0.1f; |
| float value2 = 2.1f; |
| value1 -= 0.09f; |
// Should be 0.01 |
| value2 -= 2.09f; |
// Should be 0.01 |
| cout << value1 - value2 << endl; |
// Should output zero |
| return 0; |
|
| } |
|
The value displayed should be zero, but on my computer this program produces the following:
7.45058e-009
The reason for the error is that none of the numerical values is stored exactly. If you add code to output the values of
value1
and
value2
after they’ve been modified, you should see a discrepancy between them.
Of course, the final difference between the values of
value1
and
value2
is a very small number, but you could be using this totally spurious value in other calculations in which the error could be amplified. If you multiply this result by 1010, say, you’ll get an answer around 7.45, when the result should really be zero. Similarly, if you compare these two values, expecting them to be equal, you don’t get the result you expect.
CAUTION Never rely on an exact floating-point representation of a decimal value in your program code.
Tweaking the Output
The previous program outputs the floating-point value in a very sensible fashion. It gave you 5 decimal places, and it used scientific notation (that is, a mantissa and an exponent). However, you could have chosen to have the output displayed using “normal” decimal notation by employing some more output manipulators.