Flylib.com

Books Software

 
 
 

2.2 Signed Magnitude versus Two s-Complement

   

 
Java Number Cruncher: The Java Programmer's Guide to Numerical Computing
By Ronald  Mak

Table of Contents
Chapter  2.   How Wholesome Are the Integers?

2.2 Signed Magnitude versus Two's-Complement

How does the Java virtual machine encode integer values internally in binary?

Positive values are straightforward. If we imagine that Java has a primitive integer type "nybble" (half a byte) of 4-bit integer values, then the bit patterns for the values 0 through 7 are

0  0000
1  0001
2  0010
3  0011
4  0100
5  0101
6  0110
7  0111

We reserve the leftmost bit to represent the sign: 0 for positive and 1 for negative.

Now, what about the negative numbers ? One encoding format, signed magnitude, simply sets the sign bit to 1:

C0  1000
C1  1001
C2  1010
C3  1011
C4  1100
C5  1101
C6  1110
C7  1111

But signed magnitude has two undesirable features. First, there are two zeros, positive (bit pattern 0000) and negative (bit pattern 1000). Second, we can't use the normal binary addition logic when we have negative values for example,

6  0110        C3  1011

C3


1011


C2


1010

1  0001         5  0101

Clearly, the preceding sums are wrong. Special negative number logic would be required to get the correct answers.

Another encoding format is two's-complement. It encodes the positive values the same way as signed magnitude, with the leftmost bit as the sign. However, it forms each negative value by complementing each bit of the positive value and then adding 1. So, for example, to form the two's-complement representation of -6,

Start with positive 6:

0110

Complement each bit:

1001

Add 1:

1

Gives negative 6:

1010

All of the negative values are encoded as follows :

C1  1111
C2  1110
C3  1101
C4  1100
C5  1011
C6  1010
C7  1001
C8  1000

There is only a single 0, and there is room for another negative value, -8. Now, we can also use the normal binary addition logic when we have negative values and still get the correct answers:

6  0110        C3  1101

C3


1101


C2


1110

3  0011        C5  1011

The Java virtual machine uses the two's-complement format for its byte, short, int, and long values. A value of the char type does not have a sign bit all 16 bits encode zero or a positive value.


   
Top
 
   

 
Java Number Cruncher: The Java Programmer's Guide to Numerical Computing
By Ronald  Mak

Table of Contents
Chapter  2.   How Wholesome Are the Integers?


2.3 Whole Numbers versus Integer Numbers

In Chapter 1, we emphasized how floating-point numbers are not the same as the real numbers of pure mathematics. So far, we've conceded that Java's integer numbers differ from pure math's whole numbers in a major way?athe integer numbers are not infinite. Well, at least we don't have to worry about roundoff errors! But how does the finiteness of the integer types affect integer arithmetic?

We first learned how to add and subtract in grade school by using a number line. For example, Figure 2-1 shows that 2 + 3 = 5.

Figure 2-1. 2 + 3 = 5 on the number line.

graphics/02fig01.gif

Figure 2-2 shows that 6 - 4 = 2.

Figure 2-2. 6 - 4 = 2 on the number line.

graphics/02fig02.gif

The number line extends infinitely in both the positive and negative directions.

But Java's integers are not infinite. When we add 1 to the maximum, or most positive, value of an integer type, the sum "wraps around" to the minimum, or most negative, value of that type. So, instead of an infinite linear number line, we should use a circular arrangement, like a clock face.

Figure 2-3 shows how we arrange the values of our pretend nybble integer type. The negative values are in the two's-complement format. Note how the binary values simply increment by 1, from 0000 through 1111 (decimal 0 through §C1), as we move clockwise around the face. In particular, when we add 1 to 7 (binary 0111), the most positive value, the sum wraps around to §C8 (binary 1000), the most negative value.

Figure 2-3. Type nybble's values arranged on a clock face.

graphics/02fig03.gif

Figure 2-4 shows 2 + 3 = 5 on the clock face. Compare this with Figure 2-1.

Figure 2-4. 2 + 3 = 5 on the clock face.

graphics/02fig04.gif

Figure 2-5 shows 6 - 4 = 2. Compare this with Figure 2-2.

Figure 2-5. 6 - 4 = 2 on the clock face.

graphics/02fig05.gif

The virtual machine doesn't consider crossing a boundary between the positive and the negative numbers to be an error, so in nybble arithmetic, 5 + 4 really is -7, as shown in Figure 2-6. Therefore, integer arithmetic does not throw overflow exceptions.

Figure 2-6. 5 + 4 = -7 on the clock face.

graphics/02fig06.gif

Adding two large positive values of an integer type can give a negative sum. Multiplying large positive values means going around the clock face several times. The product can be either positive or negative.

Overflows can be silent killers of integer arithmetic! Program 2 §C1 shows the effects of overflow and of division by zero with int values. See Listing 2-1.

Listing 2-1 The effects of integer overflow and division by zero.
package numbercruncher.program2_1;

/**
 * PROGRAM 2-1: Integer Overflow
 *
 * Show the effects of integer overflow and of division by zero.
 */
public class IntegerOverflow
{
    public static void main(String args[])
    {
        int big = 2147483645;

        for (int i = 1; i <= 4; ++i) {
            System.out.println(big + " + " + i + " = " + (big + i));
        }
        System.out.println();

        for (int i = 1; i <= 4; ++i) {
            System.out.println(big + " * " + i + " = " + (big*i));
        }
        System.out.println();

        int dze = big/0;
    }
}

Output:

2147483645 + 1 = 2147483646
2147483645 + 2 = 2147483647
2147483645 + 3 = -2147483648
2147483645 + 4 = -2147483647

2147483645 * 1 = 2147483645
2147483645 * 2 = -6
2147483645 * 3 = 2147483639
2147483645 * 4 = -12

java.lang.ArithmeticException: / by zero
       at
numbercruncher.program2_1.IntegerOverflow.main(IntegerOverflow.java:24)
Exception in thread "main"

   
Top