CIS Logo SVC Logo

   Computing & Information Systems
   Department

 

Schoology Facebook        Search CIS Site      Tutorials

Software Design Using C++



Arithmetic and Formatting of Output in C++



Arithmetic


Arithmetic is often used to compute an answer that we need to print, store in a variable, write to a file, etc. For example, to convert a Centigrade temperature to Farenheit we might use the following C++ assignment statement. Here CentigradeTemp is the Centigrade temperature known in advance and FarenheitTemp is the calculated Farenheit temperature. Notice how closely this C++ statement corresponds to the usual mathematical formula.


FarenheitTemp = 32.0 + 9.0 * CentigradeTemp / 5.0;

The overall form of the above assignment statement is "variable = expression". As you know, an assignment statement takes the value of the expression on the right hand side of the = operator and copies that value into the variable on the left hand side. The expression on the right hand side can be a very simple one, such as a number, a variable, or a constant. (You will learn about constants in a later section of these web pages. Follow the link in the previous sentence if you want to look at them now.) An expression can also be more complex, such as the one used above. That one used the multiplication operator *, the division operator /, as well as the addition operator +. It also contained three literal numbers and one variable.

You probably realize that it is also important to know in what order the arithmetic operators are done. Happily, C++ generally follows the same order of operations used in ordinary algebra. Thus, in our FarenheitTemp calculation, we do the * first, the / second, and the + last. This is because multiplication and division come before addition and subtraction. Multiplication and division have the same precedence, so they are simply done in left to right order.

The table below gives some additional examples of assignment statements. The expressions on the right hand sides vary in complexity. The variables and constants use in the table might be declared as follows:


const float TAXRATE = 0.06;
int k, Num, LastIndex, Count;
char Ch;
float Average, Total, Value;

Note how simple it is to set up a constant such as TAXRATE. If the constant is declared inside of a function, then it is only available in that function. (That is, it is a local constant.) If the constant is set up near the top of a C++ file, before any of the functions, then that constant is global (is available in any of the functions of this file).

Assignment statement Comment
Num = 156; 156 is a literal number
Ch = 'B'; 'B' is a character literal
Value = TAXRATE; TAXRATE is a constant
k = LastIndex; LastIndex is a variable
Average = Total / Count; Total and Count are variables
Count = Count + 1; Increments Count by 1

The first example in the table copies the literal number 156 into the variable Num. The second example copies the literal character 'B' into the char variable Ch. In both cases, it might be better to use a constant instead of a literal value. The third example shows how a constant might be used. It copies the TAXRATE constant into the float variable Value. The next example copies the value of the LastIndex variable into the int variable k. The next-to-last example finds the value of the expression Total / Count, which is the quotient when Total is divided by Count, and copies that into the float variable Average. Since Total is a float and Count is an int, floating point division is used. (If both values had been integers, then integer division would have been used. This would result in a whole number quotient. Essentially this is the floating point quotient with the part following the decimal point truncated off.) This example shows the typical way to calculate an average, though we have to be careful if Count could be zero. If that could happen we would need to use an IF statement to skip the division in the case when Count is zero. In C++ as in ordinary algebra, division by zero is not allowed. Finally, the last example shows one way to increment a variable by 1. The value of the expression on the right side is one bigger than Count. That value is then assigned back into Count, changing it to one bigger than it had been. Below we will see a shorter way to increment a variable.

Let's look at a more complete example, the arithmetic.cpp test program. This program computes and prints various nonsense values just to show how to do arithmetic, either in an assignment statement or in an output statement. (Recall that you can directly output the value of an expression.) Take a look at this program under the above link and then examine the output as shown here:


Test 1:
IntNum initially is 4
IntAnswer = IntNum + 5 puts into IntAnswer the value 9

Test 2:
After doing IntAnswer++, printing IntAnswer gives 10

Test 3:
We reset IntAnswer to value 50
Putting IntAnswer++ inside an output statement gives 50
Afterwards, the value of IntAnswer is 51

Test 4:
We reset IntAnswer to value 22
Putting ++IntAnswer inside an output statement gives 23
Afterwards, the value of IntAnswer is 23

Test 5:
We reset IntNum to value 4
Printing 2 * IntNum - 3 gives 5

Test 6:
We reset IntNum to value 4
Printing 2 * (IntNum - 3) gives 2

Test 7:
IntAnswer = 15 / 4 puts into IntAnswer the value 3

Test 8:
FloatAnswer = 15 / 4 puts into FloatAnswer the value 3

Test 9:
FloatAnswer = 15.0 / 4.0 puts into FloatAnswer the value 3.75

In Test 1 above, IntAnswer = IntNum + 5 is used to put 5 more than the value of IntNum into IntAnswer. Since IntNum has the value 4, the value 9 is placed into IntAnswer and is then printed.

In Test 2, the ++ operator is used to increment a variable. The ++ can either be placed before or after the variable, though the meaning is slightly different depending on where the ++ is placed. Here we use IntAnswer++ on a line by itself, with the ++ after the variable. When the ++ comes after the variable, the incrementing is done after anything else in the command. Since we have nothing else on this line, all that IntAnswer++ does is to increment the value of IntAnswer by 1. Thus, IntAnswer is given the value 10, which we see when the next command prints it.

In Test 3, IntAnswer++ is put inside of an output statement. This time there is more to the command than the incrementing, so all of the other stuff (namely, the output) is done first and then IntAnswer is incremented. That is why this example prints 50 when it outputs IntAnswer++ and only shows 51 in a later command that outputs IntAnswer.

Test 4 is quite similar to Test 3. However, it puts the ++ in front of the variable. Having the ++ before the variable means that the incrementing of the variable happens before anything else in the command. Since our command has ++IntAnswer inside of an output statement, the incrementing of IntAnswer to 23 is done before the output is done. Thus we see 23 in the output.

Test 5 prints the value of the expression 2 * IntNum - 3. This is a case where we have to know the precedence of the arithmetic operators. Since multiplication comes before subtraction (as it has higher priority than subtraction), this code does 2 times 4 to get 8 and then does 8 minus 3 to get a result of 5. Thus our output statement prints 5 as the value of the expression.

Test 6 is almost the same as Test 5. The only change is that it puts parentheses around IntNum - 3 to force the subtraction to be done before the multiplication. (In general, arithmetic inside of parentheses is done before arithmetic not enclosed in parentheses. If there are parentheses inside of parentheses, the innermost set of parentheses is handled first.) In our test, then, we first do 4 minus 3 to get 1 and then do 2 times the 1 to get an answer of 2.

In Test 7 we do IntAnswer = 15 / 4 and then print the value of IntAnswer. The output might surprise you at first. After all, isn't 15 divided by 4 the number 3.75? The actual number output is 3, however. This is because we are in the world of C++, not algebra. In C++, integer division is used if both numbers in the division are integers. Integer division chops off the decimal part in the 3.75, leaving 3 as the answer. (In general, if you use so-called "mixed-mode arithmetic" where one number is a float and the other is an int, the int is promoted to a float and then the arithmetic operation is carried out. There is more to the story, but this will suffice here.)

Test 8 might also surprise you a bit. It does FloatAnswer = 15 / 4, which you might think should produce the 3.75 floating point answer. However, remember how an assignment statement works: First, it evaluates the expression on the right-hand side, and then it copies that value into the variable on the left-hand side. We already saw above that the value of 15 / 4 is the integer 3, so this assignment statement copies the integer 3 into the float variable FloatAnswer. Thus it places 3.0 into the variable. (Your compiler may give you a warning message when you copy an int into a float variable, since the types are not the same.)

Finally, Test 9 shows you how to get that elusive 3.75 value if you really want it! Use floating point values (or one float and one int if you are willing to settle for mixed-mode arithmetic). The assignment statement FloatAnswer = 15.0 / 4.0 finds the value 3.75 for the expression on the right and then copies it into the variable on the left.

Precedence of Operators


As mentioned above, we often need to worry about which operator comes first when writing arithmetic expressions in our C++ programs. Since the most common arithmetic operators follow the same precedence rules as in algebra, you will find that many of the typical expressions that you need are natural to write. Sometimes, however, you may need to use less well-known operators. The following table should help you in those cases. It shown many (but not all) of the C++ operators for arithmetic, logical operations, etc. Those with priority 1 are handled before all of those with a larger precedence number. Those with priority 2 come after those with priority 1 but before all of the others. Those with the same priority are generally handled in a left to right fashion. Parentheses can be used to group items so that whatever is inside is handled before other items. If there are parentheses inside of parentheses it is the innermost set of parentheses that is handled first.

Operator Description Precedence
() function call 1
[] array indexing 1
++ after a variable postincrement 1
-- after a variable postdecrement 1
! Boolean NOT 2
++ before a variable preincrement 2
-- before a variable predecrement 2
- before an expression unary minus 2
* multiply 3
/ divide 3
% remainder (mod) 3
+ add 4
- subtract 4
< less than 5
> greater than 5
<= less than or equal 5
>= greater than or equal 5
== equal 6
!= not equal 6
&& Boolean AND 7
|| Boolean OR 8
= assignment 9
+= (and similar) add and assign 9

Formatting of Output


There are many ways of formatting your output to make it look nice on the screen. If you wish to print a number or other item in a certain field width you can use setw. To use it you must include the iomanip header. You do this in the same way that you include the iostream header. For example, you might place the following at the top of your code file:


#include <iostream>
#include <iomanip>
using namespace std;

Then to get something printed in a field having a certain width, say 8 characters wide, you place setw(8) inside your output statement. For example, suppose that you want to print the integer Value in a field 8 characters wide and follow that by printing the integer Total in a field also 8 characters wide. You would use something like this:


cout << setw(8) << Value << setw(8) << Total << endl;

Notice that we had to issue the setw(8) command twice, once before each item that we wanted to print in a field that was 8 wide. You can also print a string in a field of a certain width with setw. For example, we could print the literal strings "Value" and "Total" each in a field 8 characters wide. We might follow that by printing the values in the variables Value and Total. The code for this might be:


cout << setw(8) << "Value" << setw(8) << "Total" << endl;
cout << setw(8) << Value << setw(8) << Total << endl;

For example, if 85 and 443 are the values in variables Value and Total, then the above section of code would print things nicely lined up in columns as follows. Blanks are printed in front of each item as needed to pad the width to the desired width of 8.


   Value   Total
      85     443

To format floating point numbers nicely, it helps to print each of them with the same number of decimal places. This can be handled by placing the following code (just once) before the printing of the floats:


cout.setf(ios::fixed);
cout.setf(ios::showpoint);
cout.precision(2);

The ios::fixed indicates that we want to display our floating point numbers in fixed-point format (for example, 23.4), not in scientific format (such as 2.34e+001). We use showpoint to indicate that we want to see the decimal point and the digits to the right of it even if these digits are all zeros. Finally, the precision(2) says that we want to see 2 digits to the right of the decimal point.

As an example, consider the following program fragment. Assuming that we have included the iomanip header so that we can use setw, and assuming that the rest of the program is set up correctly, this section of code produces the output shown in the box below that follow the code.


float x, y, z;

x = 12.3;
y = -0.0398;
z = 456.7855;

cout << setw(12) << x << endl << setw(12) << y << endl
   << setw(12) << z << endl << endl;
   
cout.setf(ios::fixed);
cout.setf(ios::showpoint);
cout.precision(2);

cout << setw(12) << x << endl << setw(12) << y << endl
   << setw(12) << z << endl << endl;

Notice that the second set of output prints the numbers so that their decimal points are aligned vertically:


        12.3
     -0.0398
     456.785

       12.30
       -0.04
      456.79

Rounding a Number


Let's calculate something more useful than most of our short examples did so far on this page. Sometimes we need to round a number to a certain number of decimal places (often 2). If all we want to do is to round the printed number we can simply use precision as in the previous example. However, this does not round the actual number stored in a variable. If we need to store a rounded value in a variable, we need to do some arithmetic to compute the rounded value.

Take a look at the rounding.cpp example in this regard. It contains 4 somewhat different rounding functions and prints a list of numbers and their rounded values as produced by these rounding functions. In this test program, all we do is to print each rounded value. For example, we do something like this:


cout << Round1(Value);

If we want to also store the rounded value, perhaps back into the original variable, we would use code like this:


Value = Round1(Value);

Returning to the rounding.cpp example itself, the output produced by this test program is as follows:


     Value    Round1    Round2    Round3    Round4
   7.86000   7.86000   7.86000   7.86000   7.86000
   2.93600   2.94000   2.94000   2.94000   2.94000
   6.16400   6.16000   6.16000   6.16000   6.16000
   3.87500   3.88000   3.88000   3.88000   3.88000

Notice that all 4 of the rounding functions produce the same results. Let's examine these rounding functions one by one.


/* Given:  Value  a floating point number
   Task:   To round Value to 2 decimal places.
   Return: The rounded number in the function name.
*/   
float Round1(float Value)
   {
   float Product, Answer, Fraction;
   int Whole;
   
   Product = 100 * Value;
   Whole = static_cast<int> (Product);
   Fraction = Product - Whole;
   if (2 * Fraction >= 1)
      return (Whole + 1.0) / 100.0;
   else
      return Whole / 100.0;
   }

The Round1 function take Value, the floating point number to be rounded, and multiplies it by 100. For example, if Value contains 34.708, the variable Product is assigned 3470.8 as its value. The integer variable Whole is then assigned the whole number part of this. In other words, it gets 3470 as its value. Notice the use of the static cast to an int as one way to convert the float to an int. The difference between Product and Whole, namely 0.8 in our example, is placed into the variable Fraction. We next want to see if Fraction is 0.5 or bigger, and then round Value up if this is the case. One way to do this is to check if twice Fraction is greater or equal to 1. In our example, twice Fraction is 1.6, so that this is true. In such a case we round up by returning in the function name the value of (Whole + 1.0) / 100.0, which in our example gives (3470 + 1) / 100.0 = 3471 / 100.0 = 34.71, which is the correct rounded value.

If the original number in Value had been something like 5.6738, then Product would have been 567.38, Whole would have been 567, Fraction would have been 0.38, and since twice Fraction would have been 0.79 which is less than 1, we would have returned as our rounded answer Whole / 100.0 = 567 / 100.0 = 5.67, which is the correct result. (Since 0.38 is less than 0.5 we want to round down to 5.67 and not round up to 5.68.) Note the mixed-mode arithmetic in that Whole is an int but we divide by a float. This means that floating point division is used.


/* Given:  Value  a floating point number
   Task:   To round Value to 2 decimal places.
   Return: The rounded number in the function name.
*/   
float Round2(float Value)
   {
   int Temp;
   
   Temp = Value * 100.0 + 0.5;
   return Temp / 100.0;
   }

The Round2 function accomplishes the same rounding task with much less code. Let's trace it on our same two examples. In the first one, Value is 34.708, so that Temp is assigned 3470.8 + 0.5 = 3471.3. However, since Temp is an integer variable, the .3 is cut off and Temp gets 3471 as its value. (Note that we could have used a cast here, but it works OK without, though your compiler may give you a warning.) Thus we return Temp / 100.0 = 3471 / 100.0 = 34.71 as desired.

In our second example, Value is 5.6738, so that Temp is assigned 567.35 + 0.5 = 567.85, with the result that Temp contains 567, since it is an int variable. The function then returns 567 / 100.0 = 5.67 in the function name.


/* Given:   Value      a floating point number
            NumPlaces  a positive integer giving the number of
                       decimal places to which to round the answer.
   Assumes: That NumPlaces is positive.  No check is made to see
            that it really is.
   Task:    To round Value to NumPlaces decimal places.
   Return:  The rounded number in the function name.
*/   
float Round3(float Value, int NumPlaces)
   {
   float Factor;
   int Temp;
   
   Factor = pow(10.0, NumPlaces);
   Temp = Value * Factor + 0.5;
   return Temp / Factor;
   }

With the Round3 function, a second parameter was included in order to specify the number of decimal places to which to round the answer. In expected use, this NumPlaces parameter should be a positive integer, though the function will also work with a value of zero for NumPlaces, rounding Value to the nearest whole number. Note that the pow function is used to compute 10.0 to the NumPlaces power. This is a library function and requires that you include the cmath header. When NumPlaces is 2, pow(10.0, NumPlaces) is 100.0 so that the Factor that we multiply Value by is 100.0, just like in the Round2 function. In fact, the computations on the last 2 lines of Round3 are essentially the same as those in Round2.

Let's trace Round3 in the special case where NumPlaces is 0. Let's use the number 12.783 for Value. Note that Factor is given the value 1.0, Temp is assigned 12.783 + 0.5 = 13.283, so that Temp gets the value 13. (Once again, this is because Temp is an int.) Round3 then returns 13 / 1.0 = 13.0 in the function name. If we instead use 396.4 for Value but stay with 0 for NumPlaces, Temp is assigned 396.4 + 0.5 = 396.9, so that Temp gets the truncated value of 396. Round3 then returns 396 / 1.0 = 396.0 in the function name.


/* Given:   Value      a floating point number
            NumPlaces  a positive integer giving the number of
                       decimal places to which to round the answer.
   Task:    To round Value to NumPlaces decimal places.  If NumPlaces
            is not postive, Value is returned unchanged as the answer.
   Return:  The rounded number in the function name.
*/   
float Round4(float Value, int NumPlaces)
   {
   int k, Temp;
   float Factor;
   
   Factor = 1;
   for (k = 0; k < NumPlaces; k++)
      Factor = Factor * 10;
      
   Temp = Value * Factor + 0.5;
   return Temp / Factor;
   }

Our last example rounding function, Round4, is mostly the same as Round3. The only difference is that it does not use the pow function to compute 10 to the NumPlaces power. It uses a FOR loop to multiply 1 by the appropriate number of copies of 10. The rest of the rounding code is exactly the same as in the Round3 function.

Back to the main page for Software Design Using C++

Author: Br. David Carlson with contributions by Br. Isidore Minerd
Last updated: July 18, 2015
Disclaimer