Ch. 2 Supplemental

2's complement explanation

Arithmetic Operations

The rules for addition of binary numbers are straightforward:


0 + 0 = 0, 0 + 1 = 1, and 1 + 1 = 0 with a carry of 1, i.e. 1 + 1 =
10
In the same way, we can do subtractions:

0 - 0 = 0, and 1 - 1 = 0, and 0 - 1 = 1 with a carry of 1 (i.e., 0 - 1
= 10 - 1 = 01)
Notice, in this example, if we're representing 1-bit digits, we borrowed a 1 from the 2nd bit. But, since our representation is 1-bit, that 2nd bit becomes irrelevant!

Negative Numbers in the Computer

Another way to subtract, however, is by adding a negative. Let's use subtraction via negatives from decimal arithmetic as our guide. How do we subtract numbers in base-10 notation?

3 - 3 = 3 + (-3) = 0

So the key is to convert the number we're subtracting to its negative!

For this purpose, we introduce "signed 8-bit integers". Since we are limited to an 8-bit representation, we remain also limited to a total of 256 numbers. However, half of them will be negative (-128 through -1) and half will be positive (0 through 128).

The representation of signed (positive and negative) numbers in the computer is done through the so-called 8-bit 2's complement representation. In this representation, the 8th bit indicates the sign of the number (0 = +, 1 = -).

This 2's complement must conform to the regular laws of signed arithmetic. Since 3 + (-3) = 0, the same cancellation law must be verified when performing signed binary arithmetic. This is assured when constructing the 2's complement negative binary numbers through the following rule:

To find the negative of a number in 8-bit 2's complement representation, simply subtract the number from zero, i.e. (-X) = 0 - X using 8-bit binary arithmetic. That means that:

****************************************************************
2's complement is simply subtracting the number from 0 (e.g., in an 8-bit representation)
****************************************************************

For example, to represent (-3) in 8-bit 2's complement form:

Subtract the 8-bit binary representation of 3 from the 8-bit binary representation of 0 using 8-bit arithmetic (8-bit arithmetic implies that you can liberally take from, or carry into the 9th bit, since only the first 8 bits count... the 9th bit is irrelevant since it's not stored!).


DECIMAL:     0
         -   3
         = (-3)   
BINARY:     00000000
         -  00000011
         = (11111101)
Note that, in this operation, a 1 was liberally borrowed from the 9th bit and used in the subtraction! Thus, we have established that (-3) in base 2 is 11111101.

Now let's verify that 3 + (-3) = 0 using the 8-bit arithmetic.


DECIMAL: 3        + (-3)       = 0
BINARY:  00000011 + (11111101) = 00000000
Note that, in this operation, a carry of 1 was liberally lost in the 9th bit! Since the 9th bit is irrelevant, the answer is actually 00000000, as expected. The rule outlined above can be applied to both binary and hex numbers.


****************************************************************
Why use 2's complements at all? Simply because keeping track of a signed bit and adding or subtracting based on that is cumbersome and requires a lot of processing. On the other hand, representing a negative number with its 2's complement and adding that to another number is much easier and much less processor-intensive. Also, see here (http://www.cs.utk.edu/~eijkhout/pic3/ref_machine.html) which points out that without 2's complement, you have 2 zero's, both 0 and -0 (also note that adding one to the bit pattern of a negative number (i.e., incrementing its bit pattern by one, without 2's complement) would actually subtract one from that number, not add one to it).
****************************************************************


Passing parameters by value, pointer, or reference:

  1. Passing by value: separate copy
    fn(int vInt)
  2. Pass by pointer: uses same address (arrays are always passed by pointer)
    fn(int *pInt)
  3. Pass by reference: copies the contents and then writes new address into original address -- PREFERRED
    A reference variable is an "alias"; its value changes when its assigned variable changes and vice versa (i.e., a reference is simply another name for the variable):
    fn(int &rInt)

void foo(int x);   // pass by value 
void foo(int* x);  // pass using pointer 
void foo(int& x);  // pass by reference
 
// Pass by value:
int main() {
 int y = 23;
 foo(y);
 // y has not changed.
 return 0;
}
void foo(int x) {
 x = 13;
}
 
// Pass by pointer:
int main() {
 int y = 23;
 foo(&y);
 // y has changed to 13
 return 0;
}
void foo(int* x) {
 *x = 13;
}
 
// Pass by reference:
int main() {
 int y = 23;
 foo(y);
 // y has changed to 13
 return 0;
}
void foo(int& x) {
 x = 13;
}

References:


Ricky J. Sethi <rickys at sethi.org>
Last modified: Thu Jul 24 18:17:56 PDT 2003