Introduction to Binary Computers Steve Jost January 1997 Table of Contents 1. A Brief History of Computers 2. Binary and Hexadecimal Numbers 3. Decimal-to-Binary Conversion 4. Binary Arithmetic 5. Representation of Negative Numbers These early computers were called first generation computers. They were programmed in binary machine language which a difficult and error prone process. First generation computers were originally designed for scientific operations. 1952 The first high level language was invented by Dr. Grace Hopper. She developed a compiler for the language called A-2 which converted instructions into machine language. 1954 The FORTRAN (FORmula TRANslator) language was developed at IBM by a programming team headed by John Backus. FORTRAN is still widely used for scientific applications. 1959 The first second generation computers were introduced which were smaller and faster than the first generation ones. They used solid state devices such as diodes and transistors instead of vacuum tubes. In addition computers which accepted instructions in high level languages became widespread. 1959 To meet the increasing demand for data processing, the language COBOL (COmmon Business Oriented Language) was developed. This language became popular because it was written in a quasi-English form that could be more easily understood by nonprogrammers than other languages of that time. 1963 The BASIC (Beginners All Purpose Symbolic Instruction Code) language was developed at Dartmouth college by John Kemeny and Thomas Kurtz. It was introduced as a language which was easy for students to learn, and was available on a timesharing computer which allowed several users to take turns sharing the central processing unit of the computer. 1970 The C programming language was designed by Dennis Ritchie. Its name comes from the fact that it was an improved version of the language BCPL or B for short. Many applications which formerly were written in assembly language are now written in C. 1976 The first Cray supercomputer was built. It is capable of performing more than 100 million floating point operations per second (100 megaflops). Computers with the capability of performing more than 10 billion floating point operations per second (10 gigaflops) will be possible within the next ten years. 2. Binary Numbers for Computers Many electronic hardware devices have two natural states such as conducting or not conducting, magnetized or not magnetized, positive or negative, on or off, etc. Using the binary numbers 0 or 1 greatly simplifies the design of electronic computers. However, because long sequences of 0's and 1's are difficult to read and understand, binary digits are conventionally grouped to make them more comprehensible. The following table shows the terms that are sometimes used to denote various sized groups of binary digits. Number of Binary Digits Term ======================= ==== 1 bit 4 nibble 8 byte 16 word 32 longword Here are some of the common C datatypes and their properties. C Datatype Number of bits Number of bytes Minimum Value Maximum Value char 8 1 -128 127 unsigned char 8 1 0 255 short int 16 2 -32,768 32,767 unsigned short int 16 2 0 65,536 long int 32 4 -2,147,483,648 2,147,483,647 unsigned long int 32 4 0 4,294,967,296 float 32 4 -3.40 x 10^38 3.40 x 10^38 double 64 8 -1.79 x 10^308 1.79 x 10^308 The size of the datatype int depends on the particular implementation of C being used. On a mainframe or minicomputer, the likely size of an int is 4 bytes, while on a personal computer or microcomputer, its size is probably 2 bytes. As an introduction to digital computers, we will study a simplified computer called which only uses numbers of length 8 bits or 1 byte. Our machine is a Von Neumann machine in the sense that both data and instructions can be stored in its memory. The instructions are executed sequentially one at a time, with the possibility of looping back to repeat a block of instructions several times. Although modern assembly languages are much more powerful than the language of our machine in its instruction set are powerful enough to solve a wide variety of problems. 3. Decimal-to-Binary Conversion Because our machine uses 8 bit binary arithmetic, all of our examples will be with 8 bit numbers. Initially, we will only consider positive or unsigned binary numbers. Later, we will see how negative numbers can be represented with eight bits. To convert a binary number into base 10 or vice versa, it is convenient to use the Binary-Hex-Decimal conversion table shown below. A binary 1 means that that power of two is present while a 0 means that it is absent. Here is a table showing the various powers of two that we will need: Binary Decimal ======== ======= 1 1 10 2 100 4 1000 8 10000 16 100000 32 1000000 64 10000000 128 For example 01001101 = 64 + 8 + 4 + 1 = 77. To convert a decimal number to binary, the procedure is reversed: express the decimal number as a sum of powers of 2 and then write this sum as a sequence of binary bits. For example, to convert the decimal number 77 into binary, we write 77 -64 -- 13 - 8 -- 5 - 4 -- 1 - 1 -- 0 We select for each subtraction, the largest power of 2 which is less than or equal to the amount remaining. We then represent those powers of 2 present as 1 and those powers of 2 missing as 0. This gives 64 + 8 + 4 + 1 = 01001101. Because long binary numbers are hard to read, computer programmers prefer to express them in a form that is more easily read. The most common choice of notation today is the hexadecimal (base 16) representation where each four bit group of digits (nibble) is represented by a single hexadecimal digit. These digits are shown in the following Binary-Hex-Conversion table. Because we will be using the hex representation for machine code input to our machine, it is essential that this table be memorized. Binary Hex Decimal ====== === ======= 0000 0 0 0001 1 1 0010 2 2 0011 3 3 0100 4 4 0101 5 5 0110 6 6 0111 7 7 1000 8 8 1001 9 9 1010 a 10 1011 b 11 1100 c 12 1101 d 13 1110 e 14 1111 f 15 To represent a binary number in hex notation, simply replace each nibble by its corresponding hex digit: The binary numbers we consider will be 8 bit numbers, each of which can be represented by 2 hex digits. We will employ the C language representation which uses the prefix 0x (zero x) for hex numbers. For example the expression 0x5d represents the binary number 01011101. It is important to note that the internal binary representation of an integer is independent of the form that the number takes when it is printed. The binary number 01011101 looks like 93 when printed with the C format string %d, like 5d when printed with %x, and like ] when printed with %c, Exercises Assume that all binary numbers consist of 8 bits and are unsigned, that is, are in the range 0 to 255. Signed binary numbers are discussed in Section 5. 1. Convert the following binary numbers to decimal: 01101011, 01110000, 00000111, 11111111, 01010101 2. Convert the following decimal numbers to binary: 49, 7, 153, 200, 191, 128, 93 3. Convert the following hex numbers to binary: 0x41, 0x3f, 0x83, 0xef, 0x20, 0x2a, 0xbb Convert the following binary numbers to hex: 1101101, 11101101, 11010000, 00000111, 11111111 5. Binary Arithmetic The four basic operations addition, subtraction, multiplication, and division are all easily performed with binary numbers. In fact they are actually easier to perform in binary because the addition and multiplication tables are so small. Here are basic addition facts in binary. 0 + 0 = 0 0 + 1 = 1 1 + 0 = 1 1 + 1 = 10 /* Result is 0, carry 1 */ 0 x 0 = 0 0 x 1 = 0 1 x 0 = 0 1 x 1 = 1 Carrying and borrowing are also performed as in decimal arithmetic. To add the numbers 0x3a and 0x27, first convert to binary, and add from right to left, carrying 1 to the next column when the result is 10. 58 0x3a ---> 00111010 +39 +0x27 ---> 00100111 -- ---- -------- 97 0x61 <--- 01100001 To subtract two binary numbers, borrow 1 when the bottom digit is 1 and the top digit is 0. For example, to compute 0x3a - 0x27, 58 0x3a ---> 00111010 -39 - 0x27 ---> 00100111 -- ---- -------- 19 0x13 <--- 00010011 Binary multiplication is also similar to decimal multiplication. The top factor is used as a partial product for each binary 1 in the bottom factor. The top factor is shifted by as many places to the left as the power of 2 that the binary 1 represents. To multiply 0x1e by 0x06, 20 0x14 ---> 00010100 x 6 x 0x06 ---> 00000110 --- ---- -------- 000101000 Shift by 1 bit 000101000 Shift by 2 bits ------------ 120 0x78 <--- 0001111000 Only the rightmost eight bits are retained in the answer. Any bits to the left of these 8 bits are called overflow bits. In case any of the overflow bits are nonzero, an overflow has occurred and the rightmost eight bits which are retained in the answer are invalid. Because integer arithmetic operations are not checked for overflow in the C language, it is possible to obtain an incorrect answer when two numbers are multiplied or added. For example, when we multiply 58 and 39 and we store the result as unsigned char (8 bits), we obtain the answer 214 when the actual answer is 2262. The following calculation shows why: 58 0x3a ---> 00111010 x 39 x 0x27 ---> 00100111 -- ---- -------- 00111010 00111010 00111010 00111010 ------------- 0100011010110 Retain eight low order bits Only the rightmost eight bits 11010110 (hex 0xd6 or 214 decimal) are retained. Division is also performed as it is for decimal numbers. Unlike base 10 long division, no guesswork is involved to decide how many times the divisor goes into the trial dividend. Either it goes (quotient = 1) or it doesn't (quotient = 0). As an example, divide 213 (binary 1101010, hex 0xd5) by 9 (binary 00001001, hex 0x09). 10111 <-- quotient -------- 1001 ) 11010101 10010000 -------- 1000101 100100 ------- 1111 1001 ---- 110 <-- remainder The answer is 23 (binary 00010111, hex 0x17) with a remainder of 6 (binary 00000110). Exercise Convert the following hex numbers to binary, perform the following operations, and convert back. 0x45 + 0x3f, 0x5a + 0x74, 0xe2 - 0xaf, 0xa4 - 0x9c, 0x0a x 0x2f, 0x47 x 0x1b, 0xc4 / 0x2e, 0xbe / 0x19 5. Representation of Negative Numbers To represent negative numbers, we use the analogy of an automobile odometer. Because an odometer display has only five decimal digits to the left of the decimal point, only numbers in the range 0 to 99999 can be shown even though the actual number of miles may be much greater. The number 0 represents 0, 100000, 200000, etc., but it can also represent the negative numbers -100000, -200000, etc. The number 99999 represents 199999, 299999, and also -1, -100001, -200001, etc. By adopting the convention that 1 to 99999 represent positive numbers and 50000 to 99999 represent negative numbers, all numbers from starting from -50000 to 49999 can be represented. In the case of 8 bit binary numbers, we let 00000000 through 01111111 represent positive numbers and 10000000 through 11111111 represent negative numbers. By this convention, if the leftmost bit is 0, the number is positive, and if the leftmost bit is 1, the number is negative. In this way, an 8 bit binary number can represent all integers between -128 and 127. Such a representation is called a signed integer. The following table shows how to represent negative numbers in binary. Binary Hex Decimal 01111111 7f 127 01111110 7e 126 .. .. .. 00000010 02 2 00000001 01 1 00000000 00 0 11111111 ff -1 11111110 fe -2 .. .. .. 10000001 81 -127 10000000 80 -128 Converting an eight bit binary positive number into the corresponding negative one involves subtracting it from 100000000. (The eight bit representation of 100000000 is 00000000.) For example, to convert 0x05 = 00000101 to a negative number, subtract it from 100000000 to obtain 11111011. This operation is called obtaining the two's complement of a binary number. In general the two's complement of a binary number is formed by subtracting it from 2 to the power n where n is the number of bits. Another way of performing the two's complement is to complement each digit (replace 0 by 1 and 1 by 0 ) and add 1 to the result. The complement of 00000101 is 11111010 and adding 1 produces 11111011. To verify that these numbers are actually negatives of each other, we can add them to see that the sum is 100000000 = 00000000 when truncated to eight bits. The beauty of two's complement arithmetic is that no special rules are needed to accommodate negative numbers. Merely perform the operation and keep the rightmost eight bits. Here are some examples: - 29 ---> 11100011 + 42 ---> 00101010 ---- -------- 13 <--- 00001101 -29 ---> 11100011 - (-42) ---> 11010110 ----- -------- 13 <--- 00001101 (-6) ---> 11111010 x (-5) ---> 11111011 ----- -------- ...111111111111010 ...11111111111010 ...111111111010 ...11111111010 ...1111111010 ...111111010 ...11111010 --------- retain 30 <--- ...000000000011110 8 bits