Introduction to Computer Science - C++

Mathematical Operations

In the beginning computers were basically just large calculators. And even today, that is basically what they are. They do thousands of calculations a second. Because of this, the most basic part of any programming language is a set of mathematical operation. We have already seen some, like addition +.

Let me list the basic algebraic operators (notice that there is no operator to square a number or raise it to a power):

Just to make this clearer, let me show you some examples:
Assume I have the int a, then

a = 7 + 8;  // a is 15
a = 10 - 8;  // a is 2
a = 7 * 8;  // a is 56
a = 16 / 8;  // a is 2
a = 35 / 8;  // a is 4 (because a is an int, C++ rounds a down to the nearest integer, we lose the decimal)
a = 19 % 8;  // a is 3 ( 19 / 8 is 2 remainder 3, using the % gives us the remainder) 

There are also bitwise operators. What these operators do is manipulate the bits of a variable or perform logical operations on values.  To understand this we need a little background about bits and bytes.  You remember from chapter 1 that primitive data types have different sizes.  We expressed this size difference in terms of how many bytes each data type had.  A short for example is composed of two bytes, a long of four bytes.  But what are bytes? 

Normal mathematics that you have learned is decimal mathematics.  The word decimal comes from the Latin word for ten.  This is because normal mathematics is based a 10 digit number system.  The digits start at 0 and go to 9. If you want to write a number larger than 9 you need to create another column and put a 1 in it.  But imagine if you tried to express numbers with only two digits.  Such a system would be called binary mathematic, from the Latin word for two.  Your digits would go from 0 to 1.  How would you express a number larger than 1?   You would have to put a 1 in the next column (just as you did to express a number larger than 9). So, the number 2 would look like this 10. The number 3 would look like this 11.  And the number 4 would need another new column like this 100.  As you can see, we quickly need to start using a lot of columns.  For example the number 255 would look like this 11111111.

Here is a list of some decimal numbers and their binary equivalents

1 1
2 10
3 11
4 100
5 101
6 110
7 111
8 1000
9 1001
10 1010
11 1011
12 1100
13 1101
14 1110

Computers represent numbers as binary values. Even if you assign a variable the perfectly normal decimal value like 9, the computer will store the value as a binary value ( 1001 )  You may never notice this because if you ever use the variable, the computer will convert the representation of the number back into decimal. 

Each column in a binary number is called a bit  and a group of eight bits is called a byte.  So if a short has two bytes, (16 bits) then the maximum value it can contain is 1111 1111 1111 1111 binary or 65535 decimal. Every char, int, float etc. is actually a set of bits and bytes. For instance, a char is 8 bits or one byte. Usually, and int is 32 bits or 4 bytes. We can actually change variables on the level of their bits. You can perform mathematics on numbers in terms of their bits.  To do this you must use what are called bitwise operators. The idea of bitwise operators is to perform logical operation on bits in parallel columns of two different numbers. 

Here is a list of the basic bitwise operators:

The bitwise and ( & ) operator is like the regular and ( && ) operator in that it evaluates two values and returns true or false.  Remember that true is equivalent to 1 and false to 0.  So if  I write "1 & 1" I am asking are both digits true.  In this case they are both true (1) so the result is true (1).  Similarly, "1 & 0" and "0 & 0" both result in false since it is not so that both values in each comparison are true.  In one case only one value is true, and in the second case neither values are true; they are both 0.What we are saying with the & operator is look for any place in the 2 sets of bits where there is a 1 in the same column of each number. A column which has a 1 in both numbers will meet the bitwise and ( & ) condition. Therefore, that column in the resulting value will be marked with a 1.

The bitwise or is true if one or more of the values is true.  So therefore, "1 | 1" and " 1| 0" are both true.  But " 0 | 0" is falseBitwise exclusive or is true when exactly one of the two values is true, but false if both values are true or if both values are false.  So,  "0 ^ 1" is true but " 0 ^ 0" and   "1 ^ 1" are both false.

Let's see some examples.  Assume I have the unsigned short a, then

a = 9 & 8; // a is 8 Why is this? Well, in reality the decimal value 8 in binary looks like this 0000 0000 0000 1000 and 9 looks like this: 0000 0000 0000 1001 You will notice that there a whole lot of leading zeros in these numbers. Don't be startled.  I can always add some leading zeros.  007 is equivalent to 7 (Don't tell Mr Bond). I added the zeros to fill in the 2 byte length of a short. When I do bitwise operations, I affect the whole data type, so I need to think in terms of there being zeros there when I make calculations.  So, the operation
 9 & 8; 
looks like this:
  0000 0000 0000 1000
& 0000 0000 0000 1001
-------------
  0000 0000 0000 1000
Similarly, a = 19 | 5; //a will get the value 23 Because 19 is 0000 0000 0001 0011 and 5 is 0000 0000 0000 0101 
So what we actually wrote is:
  0000 0000 0001 0011
| 0000 0000 0000 0101
--------------
  0000 0000 0001 0111
How did we get to this result? Well, | is bitwise or, so we look for any place in the 2 sets of bits where either one or both bits in the same column are 1. If there is a 1, then we place a 1 in the resulting value.

Similarly,

a = 19 ^  5; //a will get the value 22  
What we actually wrote is:
  0000 0000 0001 0011
^ 0000 0000 0000 0101
--------------
  0000 0000 0001 0110
As we know,  ^ is bitwise exclusive or, so we look for any place in the 2 sets of bits where exactly one bit in the same column is 1. If there is one 1, then we place a 1 in the resulting value. We get 10110  (decimal value 22) as our result.

The last two bitwise operators also work on the whole data type.  What they do is to move all the bits in the data type to the left or to the right.  Thus, if I have the unsigned short a =5;  it would be represented in binary as 0000 0000 0000 0101.  If I shifted the values one to the left I would get 0000 0000 0000 1010 or decimal value 10.  If I reached the left most end of the data type, I would shift the numbers right off the end and loose them.  Thus if I left shifted the number 1000 0000 0000 0000 (32768 decimal) I would get 0000 0000 0000 00000 (0 decimal).  Here is how to left shift a number in C++:

 unsigned short a =5;
 a<<1;// to shift the bits one space to the left
 a<<2;// to shift the bits two space to the left

Right shifting is conceptually the same thing as left shifting, but we move the digits tot eh right. This will result in making the value smaller. For example, if I shift the value 8 (0000 1000 binary) one digit to the right I will get 4. Here is how I would do it:

short a = 8;
a = a>>1; 
If I shifted it 4 digits to the right I would get zero.
short a = 8;
a = a>>4; 

Order of Operations

You may remember something called order of operations from mathematics. This is the relative precedence of the mathematical operations. For example, if you were asked to solve this problem, what would you write as the answer?

5+6*6
If you remembered that multiplication comes before addition, you would get 5 + 36 or 41. But if you forgot that, you might do the addition first. In that case you would get a wrong answer, 66. Knowing what operation to do first is called knowing the order of operations. We can over-ride the order of operations by using paranthesis ( ). So for example,
a = 2 + 12 * 5 ; //a is 62
But
a = (2 + 12) * 5 ; //a is 70 So without going into too many examples I will present here a list of the operators we have seen so far in order from highest precedence to lowest:

Exercises

  1. Given a string of 1's and 0's , convert every set of 8 characters into their bit meaning and store in a single char. Thus given a string of 64 ones and zeros you could produce an eight letter string.

© Nachum Danzig July 2006