The solutions to most of the exercises in the book are in this Appendix. You should attempt to work the exercise before looking at the solution. But don’t allow yourself to get bogged down. If the solution does not come to you within a reasonable amount of time, peek at the solution for a hint.
A word of warning: I have proofread these solutions many times. Each time has turned up several errors. I am amazed at how difficult it is to make everything perfect. If you find an error, please email me and I will try to correct the next printing.
When reading my programming solutions, be aware that my goal is to present simple, easy-to-read code that illustrates the point. I have not tried to optimize, neither for size nor performance.
I am also aware that each of us has our own programming style. Yours probably differs from mine. If you are working with an instructor, I encourage you to discuss programming style with him or her. I probably will not change my style, but I support other people’s desire to use their own style.
a) 4567 b) 89ab c) fedc d) 0250
a) 1000 0011 1010 1111 b) 1001 0000 0000 0001 c) 1010 1010 1010 1010 d) 0101 0101 0101 0101
a) 32 b) 48 c) 4 d) 16 e) 8 f) 32
a) 2 b) 8 c) 16 d) 3 e) 5 f) 2
r = 10, n = 8, d7 = 2, d6 = 9, d5 = 4, d4 = 5, d3 = 8, d2 = 2, d1 = 5, d0 = 4.
r = 16, n = 8, d7 = 2, d6 = 9, d5 = 4, d4 = 5, d3 = 8, d2 = 2, d1 = 5, d0 = 4.
Since there are 12 values, we need 4 bits. Any 4-bit code would work. For example,
code | grade |
0000 | A |
0001 | A- |
0010 | B+ |
0011 | B |
0100 | B- |
0101 | C+ |
0110 | C |
0111 | C- |
1000 | D+ |
1001 | D |
1010 | D- |
1011 | F |
The addressing in Figure 2.1 uses only four bits. This limits us to a 16-byte addressing space. In order to increase our space to 17 bytes, we need another bit for the address. The 17th byte would be number 10000.
The range of 32-bit unsigned ints is 0 – 4,294,967,295, so four bytes will be required. If the storage area begins at byte number 0x2fffeb96, the number will also occupy bytes number 0x2fffeb97, 0x2fffeb98, 0x2fffeb99.
Keyboard input is line buffered by the operating system and is not available to the application program until the user presses the enter key. This action places two characters in the keyboard buffer – the character key pressed and the end of line character. (The “end of line” character differs in different operating systems.)
The call to the read function gets one character from the keyboard buffer – the one corresponding to the key the user pressed. Since there is a breakpoint at the instruction following the call to read, control returns to the debugger, gdb. But the end of line character is still in the keyboard buffer, and the operating system dutifully provides it to gdb.
The net result is the same as if you had pushed the enter key immediately in response to gdb’s prompt. This causes gdb to execute the previous command, which was the continue command. So the program immediately loops back to its prompt.
Experiment with this. Try to enter more than one character before pressing the enter key. It is all very consistent. You just have to think through exactly which keys you are pressing when using the debugger to determine what your call to read are doing.
four
Store a digit in every four bits. Thus, the lowest-order digit would be stored in bits 7 – 0, the next lowest-order in 15 – 8, etc., with the highest-order digit in bits 31 – 24.
No, binary addition does not work. For example, let’s consider 48 + 27:
See next answer.
No, it doesn’t work. The problem is that the range of 4-bit signed numbers in two’s complement format is −8 ≤ x ≤ +7, and (+4) + (+5) exceeds this range.
No, it doesn’t work. The problem is that the range of 4-bit signed numbers in two’s complement format is −8 ≤ x ≤ +7, and (−4) + (−5) exceeds this range.
Adding any number to its negative will set the CF to one and the OF to zero. The sum is 2n, where n is the number of bits used for representing the signed integer. That is, the sum is one followed by n zeroes. The one gets recorded in the CF. Since the CF is irrelevant in two’s complement arithmetic, the result — n zeroes — is correct.
In two’s complement, zero does not have a representation of opposite sign. (-0.0 does exist in IEEE 754 floating point.) Also, −2n−1 does not have a representation of opposite sign.
a) +85 b) -86 c) -16 d) +15 e) -128 f) +99 g) +123
a) +4660 b) -4660 c) -292 d) +2000 e) -32768 f) +1024 g) -1 h) +30767
a) 64 b) ff c) f6 d) 58 e) 7f f) f0 g) e0 h) 80
See Section E.2 for writeStr and readLn.
See Section E.2 for writeStr and readLn.
See above for int2bin. See Section E.2 for writeStr and readLn.
See above for int2bin and uDec2int. See Section E.2 for writeStr and readLn.
Using truth tables:
x | x ⋅ 1 | |
0 | 1 | 0 |
1 | 1 | 1 |
x | x + 0 | |
0 | 0 | 0 |
1 | 0 | 1 |
Using truth tables:
x | y | x ⋅ y | y ⋅ x |
0 | 0 | 0 | 0 |
0 | 1 | 0 | 0 |
1 | 0 | 0 | 0 |
1 | 1 | 1 | 1 |
x | y | x + y | y + x |
0 | 0 | 0 | 0 |
0 | 1 | 1 | 1 |
1 | 0 | 1 | 1 |
1 | 1 | 1 | 1 |
Using truth tables:
x | x ⋅ 0 | |
0 | 0 | 0 |
1 | 0 | 0 |
x | x + 1 | |
0 | 1 | 1 |
1 | 1 | 1 |
Using truth tables:
x | x′ | x ⋅ 0 |
0 | 1 | 0 |
1 | 0 | 0 |
x | x′ | x + 1 |
0 | 1 | 1 |
1 | 0 | 1 |
Using truth tables:
x | x | x ⋅ 0 |
0 | 0 | 0 |
1 | 1 | 1 |
x | x | x + 1 |
0 | 0 | 0 |
1 | 1 | 1 |
Using truth tables:
x | y | z | x ⋅ (y + z) | x ⋅ y + x ⋅ z |
0 | 0 | 0 | 0 | 0 |
0 | 0 | 1 | 0 | 0 |
0 | 1 | 0 | 0 | 0 |
0 | 1 | 1 | 0 | 0 |
1 | 0 | 0 | 0 | 0 |
1 | 0 | 1 | 1 | 1 |
1 | 1 | 0 | 1 | 1 |
1 | 1 | 1 | 1 | 1 |
x | y | z | x + y ⋅ z | (x + y) ⋅ (x + z) |
0 | 0 | 0 | 0 | 0 |
0 | 0 | 1 | 0 | 0 |
0 | 1 | 0 | 0 | 0 |
0 | 1 | 1 | 1 | 1 |
1 | 0 | 0 | 1 | 1 |
1 | 0 | 1 | 1 | 1 |
1 | 1 | 0 | 1 | 1 |
1 | 1 | 1 | 1 | 1 |
Using a truth table and letting y = x′:
x | y = x′ | y′ |
0 | 1 | 0 |
1 | 0 | 1 |
Minterms:
Minterms:
The prime numbers correspond to the minterms m2, m3, m5, and m7. The minterms m10, m11, m12, m13, m14, m15 cannot occur so are marked “don’t care” on the Karnaugh map.
2-bit “below” circuit.
x1 | x0 | y1 | y0 | F |
0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 1 | 1 |
0 | 0 | 1 | 0 | 1 |
0 | 0 | 1 | 1 | 1 |
0 | 1 | 0 | 0 | 0 |
0 | 1 | 0 | 1 | 0 |
0 | 1 | 1 | 0 | 1 |
0 | 1 | 1 | 1 | 1 |
1 | 0 | 0 | 0 | 0 |
1 | 0 | 0 | 1 | 0 |
1 | 0 | 1 | 0 | 0 |
1 | 0 | 1 | 1 | 1 |
1 | 1 | 0 | 0 | 0 |
1 | 1 | 0 | 1 | 0 |
1 | 1 | 1 | 0 | 0 |
1 | 1 | 1 | 1 | 0 |
Referring to Figure 5.27 (page 402), we see that JK = 10 is the set (state = 1) input and JK = 01 is the reset (state = 0).
Enable = 0 | Enable = 1 | ||||||||||||
Current | Next | Next
| |||||||||||
n1 | n0 | n1 | n0 | J1 | K1 | J0 | K0 | n1 | n0 | J1 | K1 | J0 | K0 |
0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 1 | 0 |
0 | 1 | 0 | 1 | 0 | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 1 |
1 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | 1 | 0 | 1 | 0 |
1 | 1 | 1 | 1 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 1 |
This leads to the following equations for the inputs to the JK flip-flops (using “E” for “Enable”):
Simplify these equations using Karnaugh maps.
Four-bit up counter.
The compiler will not use a register for the theInteger variable because the algorithm requires the address of this variable, and registers have no memory address.
When I ran this program with the input -1985229329, I got the results:
The four characters are returned as a 4-byte word and then stored in memory by main. They are then written to standard out one character at a time. Storage order in memory is little endian, so the characters are displayed “backwards.”
Use gdb to examine the values in the rbp and rsp registers just before the first and just before the last instructions are executed.
This exercise shows that the text strings and local variables are stored in different areas of memory.
Your numbers may differ.
instruction | n bytes | rax | rsi | rbp | rsp |
7f940f088a60 | 7fff24330778 | 0 | 7fff172a9618 | ||
pushq %rbp | 1 | 7f940f088a60 | 7fff24330778 | 0 | 7fff172a9610 |
movl %rsp, %rbp | 3 | 7f940f088a60 | 7fff24330778 | 7fff172a9610 | 7fff172a9610 |
movl $0xabcd1234,%esi | 5 | 7f940f088a60 | abcd1234 | 7fff172a9610 | 7fff172a9610 |
movl $0, %eax | 5 | 0 | abcd1234 | 7fff172a9610 | 7fff172a9610 |
movl %rbp, %rsp | 3 | 0 | abcd1234 | 7fff172a9610 | 7fff172a9610 |
popq %rbp | 1 | 0 | abcd1234 | 0 | 7fff172a9618 |
ret | |||||
Comments have been added. Your results may vary depending on version changes in gcc.
The assembly language program in Listing 9.6 uses esi for the y variable and edx for the z variable. If there is overflow, the call to printf changes the contents of these registers. So when the results are displayed y and/or z are incorrect.
See solution to Exercise 9
instruction | n bytes | offset | total | decimal |
7462 | 2 | 62 | 64 | +100 |
749a | 2 | 9a | 9c | -100 |
0f8426010000 | 6 | 00000126 | 0000012c | +300 |
0f84cefeffff | 6 | fffffece | fffffed4 | -300 |
Looking at the listing file:
the second byte in the jmp here1 instruction is 03, which is the number of bytes to the here1 location.
Single-stepping through the program with gdb and examining the contents of rax, rip, and pointer shows that jmp *%rax and jmp *pointer use the full address, not just an offset.
The program will probably crash. When the write function is called, it returns the number of characters written. Return values are placed in eax. Hence, the address is overwritten. In general, it is safer to use variables in the stack frame if their values must remain the same after another function is called.
With version 4.7.0 of gcc and no optimization (-O0), they both use the same assembly language for the loop:
After the program executes, the system prompt is displayed twice because the “return key” is still in the standard in buffer. This can be fixed by reading two characters.
See above for writeStr.
Note: Some students will try to create a nested loop, the outer one being executed twice. But the display messages are not nearly as nice, unless the student uses some “goto” statements. In my opinion, two separate change case loops is better software engineering because it allows maximum flexibility in the user messages. The user will generally complain about what is seen on the screen, not the cleverness of the code.
See above for writeStr and readLn.
See above for writeStr.
See Section E.11 for writeStr and readLn.
See Section E.11 for writeStr.
See Section E.11 for writeStr and readLn.
See Section E.11 for writeStr and readLn.
See above for uInt2dec and dec2uInt. See Section E.11 for writeStr and readLn.
See Section E.12 fot sInt2dec. See Section E.11 for writeStr.
See above for putInt. See Section E.12 for dec2sInt See Section E.11 for writeStr and readLn.
See above for putInt and getInt. See Section E.11 for writeStr and readLn.
See above for putInt and getInt. See Section E.11 for writeStr and readLn.
See above for putInt and getInt. See Section E.11 for writeStr and readLn.
See above for getInt. See Section E.11 for writeStr.
See Section E.11 for writeStr.
See Section E.11 for writeStr and readLn.
The following program is provided for you to work with these conversions.
a) 3f800000 b) bdcccccd c) 44faa000 d) 3b800000 e) c5435500 f) 3ea8f5c3 g) 4048f5c3
The following program is provided for you to work with these conversion.
a) +2.0 b) -1.0 c) +0.0625 d) -16.03125 e) 100.03125 f) 1.2 g) 123.449997 h) -54.320999
The bit pattern for +2.0 is 01000...0. Because IEEE 754 uses a biased exponent format, all the floating point numbers in the range 0.0 – +2.0 are within the bit pattern range 00000...0 – 01000...0. So half the positive floating point numbers are in the range 00000...0 – 00111...0, and the other half in the range 01000...0 – 01111...1.
The same argument applies to the negative floating point numbers.