CONTENTS

Appendix A. NUMBER BASES

Our method for writing numbers is based on powers of 10. For example, consider the number 2468. The 2 represents 2 thousands, the 4 represents 4 hundreds, the 6 represents 6 tens, and the 8 represents 8 ones:

graphics/aequ01.gif

One thousand is 10x10x10, which can be written as 10[3], or 10 to the 3rd power. Using this notation, we can write the preceding relationship this way:

graphics/aequ02.gif

Because our number notation is based on powers of 10, we refer to it as base 10, or decimal, notation. One can just as easily pick another number as a base. C++ lets you use base 8 (octal) and base 16 (hexadecimal) notation for writing integer numbers. (Note: 10[0] is 1, as is any nonzero number to the zero power.)

Octal Integers

Octal numbers are based on powers of 8, so base 8 notation uses the digits 0? in writing numbers. C++ uses a 0 prefix to indicate octal notation. Thus, 0177 is an octal value. You can use powers of 8 to find the equivalent base 10 value:

0177 (octal) = 1x8[2] + 7x8[1] + 7x8[0]
  = 1x 64 + 7x8 + 7x1
  = 127 (decimal)

The UNIX operating system often uses octal representation of values, which is why C++ and C provide octal notation.

Hexadecimal Numbers

Hexadecimal numbers are based on powers of 16. That means 10 in hexadecimal represents the value 16 + 0, or 16. To represent the values between 9 and hexadecimal 16, you need a few more digits. Standard hexadecimal notation uses the letters a杅 for that purpose. C++ accepts either lowercase or uppercase versions of these characters, as shown in Table A.1.

Table A.1. Hexadecimal Digits
Hexadecimal digits Decimal value Hexadecimal digits Decimal value
a or A 10 d or D 13
b or B 11 e or E 14
c or C 12 f or F 15

C++ uses a 0x or 0X notation to indicate hexadecimal notation. Thus, 0x2B3 is a hexadecimal value. To find its decimal equivalent, you can evaluate the powers of 16:

0x2B3 (hex) = 2x16[2] + 11x16[1] + 3x16[0]
  = 2x256 + 11x16 + 3x1
  = 691 (decimal)

Hardware documentation often uses hexadecimal notation to represent values such as memory locations and port numbers.

Binary Numbers

Whether you use decimal, octal, or hexadecimal notation for writing an integer, the computer stores it as a binary, or base 2, value. Binary notation uses just two digits, 0 and 1. As an example, 10011011 is a binary number. Note, however, that C++ doesn't provide for writing a number in binary notation. Binary numbers are based on powers of 2:

10011011 = 1x2[7] + 0x2[6] + 0x2[5] + 1x2[4] + 1x2[3]
  + 0x2[2] + 1x2[1] + 1x2[0]
  = 128 + 0 + 0 + 16 + 8 + 0 + 2 + 1
  = 155

Binary notation makes a nice match to computer memory, in which each individual unit, called a bit, can be set to off or on. Just identify the off setting with 0 and the on setting with 1. Memory commonly is organized in units called bytes, with each byte being 8 bits. The bits in a byte are numbered corresponding to the associated power of 2. Thus, the rightmost bit is bit number 0, the next bit is bit 1, and so on. Figure A.1, for example, represents a 2-byte integer.

Figure A.1. A two-byte integer value.

graphics/afig01.gif

Binary and Hex

Hex notation often is used to provide a more convenient view of binary data, such as memory addresses or integers holding bit-flag settings. The reason is that each hexadecimal digit corresponds to a four-bit unit. Table A.2 shows this correspondence.

Table A.2. Hexadecimal Digits and Binary Equivalents
Hexadecimal digit Binary equivalent Hexadecimal digit Binary equivalent
0 0000 8 1000
1 0001 9 1001
2 0010 A 1010
3 0011 B 1011
4 0100 C 1100
5 0101 D 1101
6 0110 E 1110
7 0111 F 1111

To convert a hex value to binary, just replace each hex digit by the corresponding binary equivalent. For example, the hex number 0xA4 corresponds to binary 1010 0100. Similarly, you easily can convert binary values to hex notation by converting each 4-bit unit into the equivalent hex digit. For example, the binary value 1001 0101 becomes 0x95.

Real World Note: What Are Big Endian and Little Endian?

graphics/common.gif

Oddly enough, two computing platforms that both use binary representation of integers might not represent the same number identically. Intel machines, for example, store bytes using the Little Endian architecture, while Motorola, RISC-based MIPS computers, and the DEC Alpha computers employ the Big Endian scheme. (However, the last two systems can be configured to use either scheme.)

The terms Big Endian and Little Endian are derived from "Big End In" and "Little End In"梐 reference to the order of bytes in a word (typically a two-byte unit) of memory. On an Intel computer (Little Endian), the low-order byte is stored first. This means a hex value such as 0xABCD would be stored in memory as (0xCD 0xAB). A Motorola (Big Endian) machine would store the same value in the reverse, so 0xABCD would be stored in memory as (0xAB 0xCD).

You, as a software engineer, should understand the word order of the platform you are targeting. Among other things, it affects the interpretation of data transmitted over a network and how data are stored in binary files. In the example above, the two-byte memory pattern 0xABCD would represent the decimal value 52,651 on a Little Endian machine and the decimal 43,981 on a Big Endian machine.

CONTENTS