The Art of Assembly Language
|
2.2 Numbering Systems
Most modern computer systems do not represent numeric values using the decimal system. Instead, they typically use a binary or two's complement numbering system. To understand the limitations of computer arithmetic, you must understand how computers represent numbers.
2.2.1 A Review of the Decimal System
You've been using the decimal (base 10) numbering system for so long that you probably take it for granted. When you see a number like "123", you don't think about the value 123; rather, you generate a mental image of how many items this value represents. In reality, however, the number 123 represents
1*102 + 2 * 101 + 3*100
or
100+20+3
In the positional numbering system, each digit appearing to the left of the decimal point represents a value between zero and nine times an increasing power of ten. Digits appearing to the right of the decimal point represent a value between zero and nine times an increasing negative power of ten. For example, the value 123.456 means
1*102 + 2*101 + 3*100 + 4*10-1 + 5*10-2 + 6*10-3
or
100 + 20 + 3 + 0.4 + 0.05 + 0.006
2.2.2 The Binary Numbering System
Most modern computer systems operate using binary logic. The computer represents values using two voltage levels (usually 0v and +2.4..5v). With two such levels we can represent exactly two different values. These could be any two different values, but they typically represent the values zero and one. These two values, coincidentally, correspond to the two digits the binary numbering system uses. Because there is a correspondence between the logic levels used by the 80x86 and the two digits used in the binary numbering system, it should come as no surprise that the PC employs the binary numbering system.
The binary numbering system works just like the decimal numbering system, with two exceptions: binary only allows the digits 0 and 1 (rather than 0..9), and binary uses powers of two rather than powers of ten. Therefore, it is very easy to convert a binary number to decimal. For each "1" in the binary string, add in 2n where "n" is the zero-based position of the binary digit. For example, the binary value 110010102 represents:
1*27 + 1*26 + 0*25 + 0*24 + 1*23 + 0*22 + 1*21 + 0*20 = 128 + 64 + 8 + 2 = 20210
To convert decimal to binary is slightly more difficult. You must find those powers of two that, when added together, produce the decimal result. One method is to work from a large power of two down to 20. Consider the decimal value 1359:
-
210=1024; 211=2048. So 1024 is the largest power of two less than 1359. Subtract 1024 from 1359 and begin the binary value on the left with a "1" digit. Binary = "1"; decimal result is 1359 – 1024 = 335.
-
The next lower power of two (29 = 512) is greater than the result from above, so add a "0" to the end of the binary string. Binary = "10"; decimal result is still 335.
-
The next lower power of two is 256 (28). Subtract this from 335 and add a "1" digit to the end of the binary number. Binary = "101"; decimal result is 79.
-
128 (27) is greater than 79, so tack a "0" to the end of the binary string. Binary = "1010"; decimal result remains 79.
-
The next lower power of two (26 = 64) is less than 79, so subtract 64 and append a "1" to the end of the binary string. Binary = "10101"; decimal result is 15.
-
15 is less than the next power of two (25 = 32) so simply add a "0" to the end of the binary string. Binary = "101010"; decimal result is still 15.
-
16 (24) is greater than the remainder so far, so append a "0" to the end of the binary string. Binary = "1010100"; decimal result is 15.
-
23 (eight) is less than 15, so stick another "1" digit on the end of the binary string. Binary = "10101001"; decimal result is 7.
-
22 is less than seven, so subtract four from seven and append another "1" to the binary string. Binary = "101010011"; decimal result is 3.
-
21 is less than three, so append a "1" to the end of the binary string and subtract two from the decimal value. Binary = "1010100111"; decimal result is now 1.
-
Finally, the decimal result is 1, which is 20, so add a final "1" to the end of the binary string. The final binary result is "10101001111."
If you actually have to convert a decimal number to binary by hand, the algorithm above probably isn't the easiest to master. A simpler solution is the "even/odd - divide by two" algorithm. This algorithm uses the following steps:
-
If the number is even, emit a zero. If the number is odd, emit a one.
-
Divide the number by two and throw away any fractional component or remainder.
-
If the quotient is zero, the algorithm is complete.
-
If the quotient is not zero and is odd, insert a "1" before the current string; if the number is even, prefix your binary string with zero.
-
Go back to step two above and repeat.
Fortunately, you'll rarely need to convert decimal numbers directly to binary strings, so neither of these algorithms is particularly important in real life.
Binary numbers, although they have little importance in high level languages, appear everywhere in assembly language programs (even if you don't convert between decimal and binary). So you should be somewhat comfortable with them.
2.2.3 Binary Formats
In the purest sense, every binary number contains an infinite number of digits (or bits which is short for binary digits). For example, we can represent the number five by any of the following:
101 00000101 0000000000101 .. 000000000000101
Any number of leading zero digits may precede the binary number without changing its value.
We will adopt the convention of ignoring any leading zeros if present in a value. For example, 1012 represents the number five but because the 80x86 typically works with groups of 8 bits, we'll find it much easier to zero extend all binary numbers to some multiple of 4 or 8 bits. Therefore, following this convention, we'd represent the number five as 01012 or 000001012.
In the United States, most people separate every three digits with a comma to make larger numbers easier to read. For example, 1,023,435,208 is much easier to read and comprehend than 1023435208. We'll adopt a similar convention in this text for binary numbers. We will separate each group of four binary bits with an underscore. For example, we will write the binary value 1010111110110010 as 1010_1111_1011_0010.
We often pack several values together into the same binary number. One form of the 80x86 mov instruction uses the binary encoding 1011 0rrr dddd dddd to pack three items into 16 bits: a five-bit operation code (1_0110), a three-bit register field (rrr), and an 8-bit immediate value (dddd_dddd). For convenience, we'll assign a numeric value to each bit position. We'll number each bit as follows:
-
The rightmost bit in a binary number is bit position zero.
-
Each bit to the left is given the next successive bit number.
An 8-bit binary value uses bits 0..7:
X7 X6 X5 X4 X3 X2 X1 X0
A 16-bit binary value uses bit positions 0..15:
X15 X14 X13 X12 X11 X10 X9 X8 X7 X6 X5 X4 X3 X2 X1 X0
A 32-bit binary value uses bit positions 0..31, and so on.
Bit zero is the low order (L.O.) bit (some refer to this as the least significant bit). The leftmost bit is typically called the high order (H.O.) bit (or the most significant bit). We'll refer to the intermediate bits by their respective bit numbers.
|