Each place has 10 times the value of the previous one.
Depending on the number,
we might need ten decimal digits to write it:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9.
1000’s place | 100’s place | 10’s place | 1’s place |
---|---|---|---|
2 | 0 | 2 | 5 |
2 × 1000 = 2000 0 × 100 = 0 2 × 10 = 20 5 × 1 = 5 2025
Each place has 2 times the value of the previous one.
The only binary digits we will ever need to write are
0
and
1
.
A binary digit (either 0
or 1
)
is called a bit.
Today we write the two possible values of a bit as
0
or
1
.
In the days of Morse Code,
we wrote them as “dot” and “dash”.
A series of 8 bits is called a byte.
For example, 01010111
.
A series of 4 bits is called a nibble.
For example, 0101
.
1024’s place | 512’s place | 256’s place | 128’s place | 64’s place | 32’s place | 16’s place | 8’s place | 4’s place | 2’s place | 1’s place |
---|---|---|---|---|---|---|---|---|---|---|
1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 0 | 0 | 1 |
1 × 1024 = 1024 1 × 512 = 512 1 × 256 = 256 1 × 128 = 128 1 × 64 = 64 1 × 32 = 32 0 × 16 = 0 1 × 8 = 8 0 × 4 = 0 0 × 2 = 0 1 × 1 = 1 2025
On our machine
storm.cis.fordham.edu
,
an
int
occupies 32 bits.
00000000000000000000000000000000 (zero) 00000000000000000000000000000001 (one) 00000000000000000000000000000010 (two) 00000000000000000000000000000011 (three) 00000000000000000000000000000100 (four) 00000000000000000000000000000111 (seven) 00000000000000000000000000001010 (ten) 00000000000000000000000000001111 (fifteen) 00000000000000000000000000010000 (sixteen) 00000000000000000000011111101001 (two thousand twenty-five)
int
In the decimal world, left-shifting a number multiplies it by 10. For example,
7 70 700 7000
In the binary world, left-shifting a number multiplies it by 2. For example,
111 (seven) 1110 (fourteen) 11100 (twenty-eight) 111000 (fifty-six)
//The "left shift" operator << //Its left operand is always an integer (in this case, n). int n {7}; //In binary, n is 00000000000000000000000000000111 int i {n << 1}; //In binary, i is 00000000000000000000000000001110 int j {n << 2}; //In binary, j is 00000000000000000000000000011100 int k {n << 3}; //In binary, k is 00000000000000000000000000111000
places.C
demonstrates that each place in a binary number
has twice the value of the previous place.
The C++ operator
<<
is
overloaded:
that means it can do two different things:
<<
is a destination for output
(such as the familiar cout
or cerr
),
the <<
will perform output.
<<
is an int
(such as the 1
in places.C
),
the <<
will perform left-shift.
The value of the int
is already stored in binary in the computer’s memory.
To get the value of each bit individually,
we need two new operators,
>>
(right shift)
and
&
(bitwise and).
//The "right shift" operator >> //Its left operand is always an integer (in this case, n). int n {14}; //In binary, n is 00000000000000000000000000001110 int i {n >> 1}; //In binary, i is 00000000000000000000000000000111 int j {n >> 2}; //In binary, j is 00000000000000000000000000000011 int k {n >> 3}; //In binary, k is 00000000000000000000000000000001
//The "input" operator >> //Its left operand is always a source of input (in this case, cin). int n {14}; cin >> 14;
The “bitwise and” operation
is simpler than addition or subtraction,
because there is no carrying or borrowing.
In this example,
the mask 0011
gives us a result in which
only the two rightmost bits of the original number
(1010
in the top line)
survive unchanged.
The other bits of the original number get zeroed out.
1010 the original number & 0011 Allow only the 2 rightmost bits of the original number to survive. 0010 The rest of the bits in the result are all 0s.
//The "bitwise and" operator & int n {10}; //In binary, n is 00000000000000000000000000001010 int m {3}; //In binary, m is 00000000000000000000000000000011 int j {n & m}; //In binary, j is 00000000000000000000000000000010
binary.C
outputs the 32 bits of an
int
one at a time,
from left to right.
During each iteration,
we shift a different bit of the original number
n
to a position all the way on the right,
and then use bitwise and to assasinate all the other bits.
Only the bit all the way on the right survives to be output.
bintodec1.C
.
Type control-d
to indicate “end of input”
and terminate this program.
(Hold down the control key while you tap the lowercase
d
key.)
If you type hello
instead of a binary number, the
stoi
function will throw the exception
invalid_argument
.
If no one catches this exception,
the program will be killed by a Linux signal,
which is a (usually deadly) little bullet carrying a number.
If a program is killed by a signal,
you can subtract 128 from the program’s exit status number
to find the number of the signal that killed the program.
On our machine,
the abort signal
SIGABRT
is signal number 6.
Try it:
Input an integer in binary (or control-d to end): hello terminate called after throwing an instance of 'std::invalid_argument' what(): stoi Aborted (core dumped) [mark@mark binary]$ echo $? 134
bintodec2.C
will catch the exception
and give the user an explanation and another chance.
bintodec3.C
will catch two different types of exceptions,
invalid_argument
and
out_of_range
.
bintodec4.C
will catch every type of exception.
We wrote the number 2025 with only four digits in decimal,
2025
but we needed 11 digits to write it in binary:
11111101001
We usually consider bits in groups of 4 or 8 at a time,
so let’s add five leading 0
s
to make 16 bits:
0000011111101001
Binary numbers usually need many more digits than decimal. That’s why they invented hexadecimal digits. Each hexadecimal digit (hex digit) stands for a series of four bits (one nibble). There are 16 possible hexadecinal digits:
hex digit |
nibble (4 bits) |
---|---|
0 |
0000 |
1 |
0001 |
2 |
0010 |
3 |
0011 |
4 |
0100 |
5 |
0101 |
6 |
0110 |
7 |
0111 |
8 |
1000 |
9 |
1001 |
A |
1010 |
B |
1011 |
C |
1100 |
D |
1101 |
E |
1110 |
F |
1111 |
We can now write out 16-bit number
(2025 = 0000011111101001
)
with only 4 hex digits (07E9
):
32768’s place | 16384’s place | 8192’s place | 4096’s place | 2048’s place | 1024’s place | 512’s place | 256’s place | 128’s place | 64’s place | 32’s place | 16’s place | 8’s place | 4’s place | 2’s place | 1’s place | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
binary | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 0 | 0 | 1 |
hex | 0 | 7 | E | 9 |
Exercise.
Write the following 32-bit integer as 8 hexadecimal digits.
Do they spell anything?
(This example from
The Practice of Programming
(1999)
by Brian W. Kernighan and Rob Pike, p. 159.)
11011110 10101101 10111110 11101111
Exercise.
Change
binary.C
to output the
int
in hexadecial instead of binary.
During the first iteration of the loop,
shift the int
28 places to the right.
During the first iteration of the loop,
shift the int
24 places to the right.
During the first iteration of the loop,
shift the int
20 places to the right.
During the seventh (and next-to-last) iteration of the loop,
shift the int
4 places to the right.
During the eighth (and last) iteration of the loop,
shift the int
0 places to the right.
See the pattern?
Afer each shift,
zero out all but the 4 lowest bits of the shifted value.
Only the 4 lowest bits should survive unchanged.
Use these surviving 4 bits
as a subscript into the following array of 16 string
s:
const string hex[] { //Remember to #include <string> "0", //0000 "1", //0001 "2", //0010 "3", //0011 //etc. "D" //1101 "E" //1110 "F" //1111 };
Answer:
hexadecimal.C
Exercise.
Change
hexadecimal.C
to output the
int
in octal.
Each octal digit is an abbreviation for three bits.
There are eight possible ocal digits:
octal digit |
3 bits |
---|---|
0 |
000 |
1 |
001 |
2 |
010 |
3 |
011 |
4 |
100 |
5 |
101 |
6 |
110 |
7 |
111 |
Answer:
octal.C
.
Type control-d
into the following programs
to signal that you’re done typing.
dectohex.C
:
convert base 10 to base 16.
hextodec.C
:
convert base 16 to base 10.
bc
is the binary calculator;
-l
is its math library.
ibase
is the input base;
obase
is the output base.
Convert decimal to hexadecimal:
bc -l obase=16 2025 7E9 2026 7EA control-d
Convert hexadecimal to decimal:
bc -l ibase=16 7E9 2025 7EA 2026 control-d
Convert decimal to binary:
bc -l obase=2 2025 11111101001 2026 11111101010 control-d
Convert binary to decimal:
bc -l ibase=2 11111101001 2025 11111101001 2026 control-d