Mathematics for Computer Science 201-N11 • CEGEP, Montreal
Corrected exercises: number systems in computing (201-N11)
This is the corrected exercise set on number systems for Mathematics for Computer Science, 201-N11, the mathematics course taken by CEGEP students in computer science programs (Computer Science Technology, and Computer Science and Mathematics). Part A covers the basics: positional weights and reading a number in its base, repeated division and repeated multiplication to convert from decimal, binary arithmetic worked by hand, two's complement and its asymmetric range, then overflow and the rule that detects it. Two complete labs take the whole route again in base 8 (exercise 5) and in base 16 (exercise 6): expanded notation, conversions from octal and hexadecimal to decimal and back, addition, 8's and 16's complements, subtraction with borrows, long multiplication and a round trip checked in decimal, all the way to Linux permissions chmod 755.
Part B moves up to exam level: hexadecimal as a compact way of writing binary, with masks and shifts (exercise 8), the ASCII, BCD and Gray codes and the parity bit, with the limitation that leads to the Hamming code (exercise 9), a problem on screen colours and memory capacity (exercise 11), and the complete construction of an IEEE 754 single-precision floating-point number (exercise 12).
The thread of the set: the base gives the weight of each position, so converting means weighing. Every conversion is checked by adding up the weights again, and that check catches both the remainders read in the wrong order and the groups of bits cut from the left.
The pitfalls named explicitly in the solutions: believing that a bit pattern carries its own interpretation, forgetting that the signed range is asymmetric because zero takes up one slot, confusing the unsigned carry with signed overflow (exercise 7), and thinking that 0.1 will end up being written exactly in binary if enough bits are added (exercises 2 and 10).
Self-checking setType your answers and check them question by question: the page tells you right or wrong before you open the solution. With an account, every answer right on the first try earns points, and your right answers stay filled in when you come back.
•In base b, the digit in position k has weight bk; after the radix point, the weights are b−1,b−2,…
•Decimal to base b: repeated division, remainders read from BOTTOM TO TOP. Fractional part: repeated multiplication, integer parts read from TOP TO BOTTOM.
•One hexadecimal digit is 4 bits, one octal digit is 3 bits. Always group the bits starting from the RIGHT.
•Unsigned, on n bits: from 0 to 2n−1. In two's complement: from −2n−1 to 2n−1−1.
•Two's complement of x: invert all the bits, then add 1. The resulting pattern equals 2n−x.
•Signed overflow: both operands have the same sign and the result has the opposite sign. Two operands of opposite signs never overflow.
•AND to clear bits, OR to set them, XOR to toggle them.
•Shifting left by k positions: multiplication by 2k. Shifting right: integer division by 2k.
•A terminating decimal has a terminating binary expansion only if its reduced denominator is a power of 2.
•IEEE 754 single precision: 1 sign bit, 8 exponent bits with a bias of 127, 23 mantissa bits, with an implicit leading 1. Integers are exact up to 224.
Part A: the basics (/70)
Exercise 1: Positional weights: reading a number in its base
In a base b, the digit in position k (counted from the right, starting at 0) has weight bk. Converting to decimal means weighing: multiply each digit by the weight of its position and add. The grid below recalls the eight weights of a byte.
a) Convert 101101102 to decimal.
b) Convert 3578 to decimal.
c) Convert 2F516 to decimal.
d) Convert 1101.1012 to decimal.
e) What is the largest unsigned integer that can be represented on n bits? On 8 bits? On 16 bits?
Show the solution
Answers
a)182
b)239
c)757
d)13.625
e)2n−1, that is 255 on 8 bits and 65535 on 16 bits
a)
Write the weights above the bits: 128,64,32,16,8,4,2,1. The bits equal to 1 are those of weight 128, 32, 16, 4 and 2. Sum: 128+32+16+4+2=182. Quick check: the most significant bit is 1, so the number is at least 128; the least significant bit is 0, so the number is even. 182 satisfies both.
b)
In base 8, the weights are 64,8,1. So 3578=3(64)+5(8)+7(1)=192+40+7=239. Check: the largest digit used is 7, which is allowed in base 8; an 8 or a 9 in an octal numeral would be a mistake in the question.
c)
In base 16, the weights are 256,16,1, and F stands for 15. So 2F516=2(256)+15(16)+5(1)=512+240+5=757. The letters A to F stand for 10 to 15: that is the only thing to memorize in hexadecimal.
d)
The integer part 11012 is 8+4+1=13. After the binary point, the weights become negative powers: 2−1=0.5, then 2−2=0.25, then 2−3=0.125. The bits are 1,0,1, so the fractional part is 0.5+0.125=0.625. Total: 13.625. The rule is the same on both sides of the point; only the sign of the exponent changes.
e)
On n bits there are 2n combinations, numbered from 0 to 2n−1: the largest unsigned integer is therefore 2n−1. On 8 bits, 255; on 16 bits, 65535. Classic pitfall: answering 2n and forgetting that zero uses up one combination.
Tick the exercises you have done or want to review: a free account, no password, keeps your ticks and your right answers from one visit to the next, tells you which chapter to tackle next and lets you ask for the exercise you are missing. Create your space, an email is enough.
Exercise 2: From decimal to other bases: repeated division
To convert a decimal integer to base b, divide repeatedly by b and read the remainders from BOTTOM TO TOP. For a fractional part, multiply repeatedly by b and read the integer parts from TOP TO BOTTOM. The two algorithms look alike, but the reading direction is reversed: that is where half the marks are lost.
a) Convert 156 to binary by repeated division and check with the weights.
b) Convert 156 to octal, then to hexadecimal.
c) Convert 0.6875 to binary.
d) Try to convert 0.1 to binary. What happens?
e) Convert 1000 to hexadecimal.
f) What consequence does question d) have for a program that tests 0.1+0.2=0.3?
Show the solution
Answers
a)156=100111002
b)156=2348=9C16
c)0.6875=0.10112
d)Repeating expansion: 0.1=0.000112, never terminating
e)1000=3E816
f)Never compare two floats with strict equality: test ∣x−y∣<ε, and count money in cents, with integers
a)
156=2(78)+0; 78=2(39)+0; 39=2(19)+1; 19=2(9)+1; 9=2(4)+1; 4=2(2)+0; 2=2(1)+0; 1=2(0)+1. The remainders read from bottom to top give 100111002. Check with the weights: 128+16+8+4=156. The weight check is compulsory, because it catches the reading-direction error, which would give 00111001.
b)
Dividing by 8: 156=8(19)+4; 19=8(2)+3; 2=8(0)+2, hence 2348. Check: 2(64)+3(8)+4=128+24+4=156. Dividing by 16: 156=16(9)+12; 9=16(0)+9, and 12=C, hence 9C16. Check: 9(16)+12=156. Shortcut: 100111002 splits into 10011100=9C, in groups of 4 bits starting from the right.
c)
0.6875×2=1.375, keep 1; 0.375×2=0.75, keep 0; 0.75×2=1.5, keep 1; 0.5×2=1.0, keep 1, and nothing is left. Reading from top to bottom: 0.10112. Check: 0.5+0.125+0.0625=0.6875. The conversion stops here because 0.6875=1611 has a denominator that is a power of 2.
d)
0.1×2=0.2; 0.2×2=0.4; 0.4×2=0.8; 0.8×2=1.6; 0.6×2=1.2; 0.2×2=0.4, and we are back to a state already seen. The expansion is repeating: 0.1=0.000112, with no end. The reason is arithmetic: 0.1=101 and 10 contains the factor 5, which is not a power of 2. A terminating decimal has a terminating binary expansion only if its reduced denominator is a power of 2.
e)
1000=16(62)+8; 62=16(3)+14, and 14=E; 3=16(0)+3. Hence 3E816. Check: 3(256)+14(16)+8=768+224+8=1000.
f)
The computer does not store 0.1 but its infinite binary expansion rounded to the number of bits available. Three separate roundings occur, for 0.1, for 0.2 and for 0.3, and nothing guarantees that the sum of the first two lands exactly on the third: in practice it does not. The conclusion fits in one rule: never compare two floating-point numbers with strict equality; test ∣x−y∣<ε instead. For money, work in cents with integers.
The four operations are worked in binary exactly as in decimal, with a tiny addition table: 0+0=0, 0+1=1, 1+1=10, 1+1+1=11. The carry propagates the same way. Every result must be checked in decimal, without exception.
a) Set up and compute 101102+11012.
b) Set up and compute 1101012−101102.
c) Set up and compute 10112×1012.
d) Carry out the division 11012÷102 and give the quotient and the remainder.
e) What happens to a binary number when a 0 is appended on the right? Three zeros?
Show the solution
Answers
a)1000112=35
b)111112=31
c)1101112=55
d)Quotient 1102=6, remainder 1
e)One zero multiplies by 2, three zeros by 23=8
a)
Align on the right: 10110 is 22 and 1101 is 13. Column by column from the right: 0+1=1; 1+0=1; 1+1=10, write 0 and carry 1; 0+1+1=10, write 0 and carry 1; 1+0+1=10, write 0 and carry 1; the carry remains, write 1. Result: 1000112. Check: 32+2+1=35 and 22+13=35.
b)
110101 is 53 and 10110 is 22. Borrow as in decimal, a borrow being worth 2 in the column that receives it. From the right: 1−0=1; 0−1 forces a borrow, 10−1=1; then 1−1 minus the borrow forces another borrow, 11−1−1=1; then 0−0 minus the borrow borrows again, 10−0−1=1; then 11−1−1=1 once more; finally 1−0−1=0. Result: 111112. Check: 16+8+4+2+1=31 and 53−22=31. A result of 11111 is not suspicious: it is 25−1.
c)
1011 is 11 and 101 is 5. Binary multiplication needs no table: each bit of the multiplier gives either a shifted copy of the multiplicand or a row of zeros. Here: 1011 (bit of weight 1), 000000 (bit of weight 2, zero), 101100 (bit of weight 4, so shifted two positions). Sum: 1011+101100=1101112. Check: 32+16+4+2+1=55 and 11×5=55.
d)
1101 is 13 and 10 is 2. Dividing by 102 means shifting one position to the right: the quotient is 1102=6 and the bit pushed out, here 1, is the remainder. Check: 2(6)+1=13. Dividing by a power of 2 is a shift, which explains why compilers replace n/2 with a shift when n is an unsigned integer.
e)
Appending a 0 on the right shifts every bit one position to the left: each bit sees its weight doubled, so the number is multiplied by 2, not by 10. Three zeros multiply by 23=8. It is the same mechanism as in decimal, where appending a zero multiplies by 10, that is, by the base. Remember: the factor is always the base, never ten.
On n bits, two's complement represents negative numbers without a separate sign: −x is written as the pattern of 2n−x. The most significant bit then acts as a sign indicator, and ordinary addition keeps working without any change to the circuit. The wheel below shows the 16 patterns of 4 bits: moving one step forward adds 1, and you go past the top with no break.
a) Write −37 in two's complement on 8 bits, showing both steps.
b) The pattern 10110100 is read as a signed integer on 8 bits. What is its value?
c) What is the range of signed integers on 8 bits? Why is it not symmetric?
d) Compute 45−37 using only an addition on 8 bits.
e) On 4 bits, what is the opposite of −8? What does this case reveal?
Show the solution
Answers
a)−37=110110112=DB16, whose unsigned reading is 219=256−37
b)−76
c)From −128 to +127: zero takes up a pattern on the positive side
d)45+110110112=8, the carry out being discarded
e)The opposite of −8 is −8: negation is not total
a)
Step 1: write 37 on 8 bits. 37=32+4+1, so 00100101. Step 2: invert all the bits, which gives 11011010, then add 1: 11011011. Numerical check: 11011011 is 128+64+16+8+2+1=219, and 219=256−37, which is exactly the definition. In hexadecimal, DB.
b)
The most significant bit is 1, so the number is negative. Two methods. Direct method: read the pattern as unsigned, 10110100=128+32+16+4=180, then subtract 256: 180−256=−76. Complement method: invert, 01001011, add 1, 01001100=64+8+4=76, so the pattern stood for −76. Both give the same result, and that is the check to do.
c)
From −128 to +127. There are 256 patterns; half of them, those whose most significant bit is 0, encode 0 to 127; the other half encode −128 to −1. The asymmetry comes from zero taking up a slot on the positive side: 127 patterns remain for the positive numbers and 128 for the negative ones. That is precisely the advantage of two's complement over representations with a separate sign bit, which have two zeros and waste a pattern.
d)
45=00101101. Add to it the representation of −37, namely 11011011. Binary addition gives 100001000 over nine columns: the carry out of position 8 is simply discarded, and what remains is 00001000=8. Check: 45−37=8. That is the whole point of two's complement: the adder circuit also serves as the subtractor, give or take an inverter.
e)
On 4 bits, the range is −8 to +7. The opposite of −8 should be +8, which does not exist in the range. Applying the recipe: −8 is written 1000; invert, 0111; add 1, 1000: we land back on −8. The case reveals that negation in two's complement is not total, and it is a real programming trap, where ∣x∣ can return a negative number for the lower bound of the range.
Exercise 5: Base 8 lab: from expanded notation to long multiplication
Octal has only eight digits, from 0 to 7, and each position has a power of 8 as its weight. Everything you can do in base 10 can be redone in base 8 with a single change: you carry as soon as you reach 8, and you borrow 8, not 10. This exercise goes through the complete route of the binary arithmetic lab, in octal: writing a number in expanded notation, converting it both ways, adding, subtracting, multiplying, then closing the loop with a round trip checked in decimal. Every result is checked by going back through decimal, and that check is what makes the difference between a correct calculation and one that only looks correct.
Tables to know or to rebuild on scrap paper: 81=8, 82=64, 83=512, 84=4096, and the reciprocals 8−1=0.125, 8−2=0.015625.
a) Write 2471.358 in expanded notation, as a sum of products of its digits by decreasing powers of 8, then give its decimal value.
b) Convert to decimal: 7358, 12048, 61.48 and 0.528.
c) Convert to octal: 200, 1000, 93.75 and 0.1. What happens for the last one?
d) Set up and compute the octal additions 3578+2468, 17458+6338+278 and 12.568+7.378.
e) We work with 4 octal digits. Define the 7's complement and the 8's complement of a number, compute the 8's complement of 03258, then use it to carry out 24618−03258 by an addition. What is the range of signed integers on 4 octal digits, and how do you recognize a negative number?
f) Set up and compute the octal subtractions 70428−35678 and 10.28−3.758, showing the borrows.
g) Set up and compute the octal multiplications 538×78, 1248×358 and 6.48×2.28.
h) Convert both numbers to octal, carry out the operation in octal, then go back to decimal to check: 345+219 and 6.5×3.25.
i) On Linux, the command chmod 755 sets the permissions of a file. Write 7558 in binary and explain what each octal digit represents. Why is octal the natural base for this encoding?
i)7558=1111011012: three parties, three bits each, read, write, execute
a)
The radix point separates the positive positions from the negative ones. On the left, moving left from the point, the weights are 80,81,82,83; on the right, 8−1 then 8−2. Hence 2471.358=2⋅83+4⋅82+7⋅81+1⋅80+3⋅8−1+5⋅8−2. Value: 2(512)+4(64)+7(8)+1+83+645=1024+256+56+1+0.375+0.078125=1337.453125. Expanded notation is not an exercise in style: it is the very definition of the base, and every conversion to decimal is just this calculation written faster.
b)
7358=7(64)+3(8)+5=448+24+5=477. 12048=1(512)+2(64)+0(8)+4=512+128+4=644: the zero is weighed too; it holds a position even though it adds nothing. 61.48=6(8)+1+84=49.5. 0.528=85+642=0.625+0.03125=0.65625. Classic pitfall: reading 0.528 as fifty-two hundredths. In base 8, the second digit after the point is worth one sixty-fourth, not one hundredth.
c)
Integer part by repeated division by 8, remainders read from bottom to top. 200=8(25)+0; 25=8(3)+1; 3=8(0)+3, hence 200=3108; check 3(64)+1(8)=200. 1000=8(125)+0; 125=8(15)+5; 15=8(1)+7; 1=8(0)+1, hence 1000=17508; check 512+7(64)+5(8)=512+448+40=1000. For 93.75, split it: 93=8(11)+5; 11=8(1)+3; 1=8(0)+1, so 93=1358; then 0.75×8=6.0, keep 6 and nothing is left, so 93.75=135.68. Check: 64+24+5+0.75=93.75. For 0.1: 0.1×8=0.8, digit 0; 0.8×8=6.4, digit 6; 0.4×8=3.2, digit 3; 0.2×8=1.6, digit 1; 0.6×8=4.8, digit 4; 0.8×8=6.4, and we are back to a state already seen. The expansion is repeating: 0.1=0.063148. No surprise: 0.1=101 and 10 contains the factor 5, which divides no power of 8. A terminating decimal has a terminating expansion in base 8 exactly when its reduced denominator is a power of 2, the same condition as in binary, because 8=23.
d)
Add column by column, and as soon as a column reaches 8, write the remainder and carry 1. First addition: ones 7+6=13=8+5, write 5 and carry 1; eights 5+4+1=10=8+2, write 2 and carry 1; 3+2+1=6. Result 6258. Decimal check: 3578=239, 2468=166, sum 405, and 6258=6(64)+2(8)+5=405. Second addition, with three terms aligned on the right: ones 5+3+7=15=8+7, write 7 and carry 1; 4+3+2+1=10, write 2, carry 1; 7+6+0+1=14, write 6, carry 1; 1+0+0+1=2. Result 26278. Check: 997+411+23=1431 and 26278=2(512)+6(64)+2(8)+7=1431. Third addition, with radix points, lining up the points: 6+7=13, write 5, carry 1; 5+3+1=9, write 1, carry 1; 2+7+1=10, write 2, carry 1; 1+0+1=2. Result 22.158. Check: 10.71875+7.484375=18.203125 and 22.158=18+81+645=18.203125. The most frequent error is carrying at 10 out of habit: 7+6 is then written down as 13, and the result is off by 8 in that column.
e)
The 7's complement of a 4-digit octal number is obtained by replacing each digit d with 7−d, with no carry at all; it is the analogue of inverting the bits. The 8's complement is the 7's complement plus 1, and it equals 84−x=4096−x: it is the analogue of two's complement. For 03258: 7's complement, digit by digit, 7−0,7−3,7−2,7−5, that is 74528; plus 1, 74538. Check: 03258=3(64)+2(8)+5=213, 4096−213=3883, and 74538=7(512)+4(64)+5(8)+3=3584+256+40+3=3883. Subtraction by addition: 24618+74538. Ones 1+3=4; 6+5=11=8+3, write 3, carry 1; 4+4+1=9, write 1, carry 1; 2+7+1=10, write 2, carry 1. We get 121348 on five digits; the carry that comes out on the left is discarded, since we work with 4 digits, and what remains is 21348. Check: 24618=1329, 1329−213=1116, and 21348=1024+64+24+4=1116. Why it works: adding 4096−x and then discarding 4096 is exactly the same as subtracting x. Signed range on 4 octal digits, that is, 12 bits: from −211=−2048 to 211−1=2047, that is, from 40008 (read as −2048) to 37778. A number is negative when its leading digit is 4 or more: the upper half of the patterns represents the negative numbers, exactly like the most significant bit in binary, since the first octal digit contains that bit. So 74538, read as a signed integer, is 3883−4096=−213.
f)
First subtraction, 70428−35678. Ones: 2<7, borrow one eight, 2+8−7=3, and the eights digit goes from 4 to 3. Eights: 3<6, borrow, 3+8−6=5, and the 64s digit must go down by 1; it is 0, so first borrow from the 512s, which go from 7 to 6, and the 64s become 8−1=7. 64s column: 7−5=2. 512s column: 6−3=3. Result 32538. Check: 70428=3618, 35678=1911, difference 1707, and 32538=3(512)+2(64)+5(8)+3=1707. Second subtraction, 10.208−3.758, padding 10.2 with a zero to line up: sixty-fourths 0<5, borrow, 0+8−5=3, and the eighths go from 2 to 1; eighths 1<7, borrow, 1+8−7=2, and the ones, which are 0, borrow from the eights, 1→0, to become 8−1=7; ones 7−3=4; eights 0−0=0. Result 4.238. Check: 8.25−3.953125=4.296875 and 4.238=4+82+643=4.296875. The trap of a cascading borrow through a zero is the same as in decimal; the only novelty is that a borrow is worth 8.
g)
Long multiplication, with the 8 times table in mind: each partial product is reduced modulo 8 and the carry can exceed 1. 538×78: 3×7=21=2(8)+5, write 5 and carry 2; 5×7+2=37=4(8)+5, write 5 then 4. Result 4558; check 43×7=301=4(64)+5(8)+5. 1248×358: by 5, 4×5=20=2(8)+4, write 4, carry 2; 2×5+2=12=8+4, write 4, carry 1; 1×5+1=6, row 6448. By 3, shifted one position: 4×3=12, write 4, carry 1; 2×3+1=7; 1×3=3, row 37408. Sum 6448+37408: 4+0=4; 4+4=8, write 0, carry 1; 6+7+1=14, write 6, carry 1; 3+1=4. Result 46048; check 84×29=2436=4(512)+6(64)+4. 6.48×2.28: multiply without the points, 648×228, and then put back as many digits after the point as there were in total in the factors, here 1+1=2. 648×2=1508 (since 4×2=8, write 0, carry 1; 6×2+1=13, write 5, carry 1); the row for the other 2, shifted, gives 15008; sum 16508; with two fractional digits, 16.508=16.58. Check: 6.5×2.25=14.625 and 16.58=14+85=14.625. The rule for placing the point is the same as in decimal, because it depends only on the number of positions, not on the base.
h)
345=8(43)+1, 43=8(5)+3, 5=8(0)+5, so 345=5318; 219=8(27)+3, 27=8(3)+3, so 219=3338. Addition: 1+3=4; 3+3=6; 5+3=8, write 0, carry 1, and write 1 in front. Result 10648, and back: 512+6(8)+4=564=345+219. The check closes the loop. Then 6.5=6.48 since 0.5=84, and 3.25=3.28 since 0.25=82. Compute 648×328: by 2, 1508; by 3, shifted: 4×3=12=8+4, write 4 and carry 1; 6×3+1=19=2(8)+3, write 3 then 2, which gives 2348, then 23408; sum 1508+23408=25108; two fractional digits: 25.108=25.18. Back: 2(8)+5+81=21.125, and 6.5×3.25=21.125. Both numbers have terminating octal expansions because their fractional parts, 21 and 41, have a power of 2 as denominator.
i)
Each octal digit is exactly 3 bits: 7=1112, 5=1012, so 7558=1111011012. The three digits encode the permissions of three parties, the owner, the group and others, and the three bits of each digit are, in order, read, write, execute. 7=111: the owner can do everything; 5=101: the group and others can read and execute, not write. Base 8 is natural here because permissions come in groups of 3 bits and an octal digit is precisely a group of 3 bits: the split needs no calculation, it is simply read off. A 644, for comparison, gives 110100100: the owner reads and writes, the others only read. That is why the binary to octal conversion works in groups of 3, and why octal survives wherever bits are handled in triples.
Exercise 6: Base 16 lab: from expanded notation to long multiplication
Hexadecimal has sixteen digits: 0 to 9, then A, B, C, D, E, F for 10 to 15. Each position has a power of 16 as its weight; you carry as soon as you reach 16, and you borrow 16. It is the base of everything displayed in computing, memory addresses, colours, the bytes of a file, because one hexadecimal digit is exactly 4 bits and a byte fits in two digits. This exercise goes through the complete route of the lab again in base 16: expanded notation, conversions both ways, addition, complement, subtraction, multiplication, and a checked round trip.
Tables to keep at hand: 162=256, 163=4096, 164=65536, 16−1=0.0625, 16−2=0.00390625; the product of two hexadecimal digits is rebuilt in decimal and then reduced modulo 16.
a) Write 3AF.C816 in expanded notation, then give its decimal value.
b) Convert to decimal: 2B16, 7D016, FFFF16, A.416 and 0.1816.
c) Convert to hexadecimal: 255, 4096, 3000, 0.8125 and 0.1. What do you notice for the last one?
d) Set up and compute the hexadecimal additions 3C16+2F16, A9F16+7E516 and 1F.816+C.A16.
e) We work with 4 hexadecimal digits. Define the 15's complement and the 16's complement, compute the 16's complement of 02D416, then use it to carry out 1A7B16−02D416 by an addition. How is this related to two's complement on 16 bits, and how do you recognize a negative number?
f) Set up and compute the hexadecimal subtractions B0516−4C916 and 10.416−7.C16, showing the borrows.
g) Set up and compute the hexadecimal multiplications 2A16×B16, 1F16×3C16 and 4.816×2.416.
h) Convert both numbers to hexadecimal, carry out the operation in hexadecimal, then go back to decimal to check: 1000−255 and 12.75×2.5.
e)16's complement of 02D416: FD2C16; the difference is 17A716=6055; range −32768 to 32767, negative as soon as the leading digit reaches 8
f)63C16 and 8.816
g)1CE16, 74416 and A.216
h)2E916=745 and 1F.E16=31.875
a)
The weights, moving left from the radix point, are 160,161,162; moving right, 16−1,16−2. Hence 3AF.C816=3⋅162+10⋅161+15⋅160+12⋅16−1+8⋅16−2, replacing A, F and C by their values 10, 15 and 12. Value: 3(256)+10(16)+15+1612+2568=768+160+15+0.75+0.03125=943.78125. The only new difficulty compared with octal is remembering that A is 10, not 1, and that F is 15, not 6.
b)
2B16=2(16)+11=43. 7D016=7(256)+13(16)+0=1792+208=2000. FFFF16=15(4096)+15(256)+15(16)+15=61440+3840+240+15=65535, and faster: four digits all at their maximum are worth 164−1=65535, the largest integer on 16 bits. A.416=10+164=10.25. 0.1816=161+2568=0.0625+0.03125=0.09375. Same pitfall as in octal: 0.1816 has nothing to do with eighteen hundredths; the second digit is worth one two-hundred-fifty-sixth.
c)
255=16(15)+15, 15=16(0)+15, two remainders of 15, that is FF16; check 15(16)+15=255, the full byte. 4096=163, so 100016: a 1 followed by three zeros, like 1000=103 in decimal. 3000=16(187)+8; 187=16(11)+11; 11=16(0)+11; remainders read from bottom to top, 11,11,8, that is BB816; check 11(256)+11(16)+8=2816+176+8=3000. 0.8125×16=13.0, digit D, and nothing is left: 0.8125=0.D16, which is consistent with 0.8125=1613. For 0.1: 0.1×16=1.6, digit 1; 0.6×16=9.6, digit 9; 0.6×16=9.6, digit 9, and so on. So 0.1=0.1916, repeating. It is the same impossibility as in binary and in octal, for the same reason: 16=24, so a decimal has a terminating expansion in base 16 if and only if it has one in base 2, that is, if its reduced denominator is a power of 2. One tenth, with its factor 5, will never qualify. You can in fact read the binary 0.000112 through the hexadecimal: 1=0001, 9=1001, and the concatenation 000110011001… does give back the pattern 0011 repeated, shifted by one position.
d)
3C16+2F16: ones C+F=12+15=27=16+11, write B and carry 1; 3+2+1=6. Result 6B16; check 60+47=107=6(16)+11. A9F16+7E516: F+5=20=16+4, write 4, carry 1; 9+E+1=9+14+1=24=16+8, write 8, carry 1; A+7+1=18=16+2, write 2, carry 1, written in front. Result 128416; check 2719+2021=4740=4096+2(256)+8(16)+4. 1F.816+C.A16, radix points lined up: 8+A=18=16+2, write 2, carry 1; F+C+1=15+12+1=28=16+12, write C, carry 1; 1+0+1=2. Result 2C.216; check 31.5+12.625=44.125=2(16)+12+162. The safe method for each column: add in decimal, subtract 16 if you go past 15, then translate the remainder into a hexadecimal digit. The pitfall is writing 27 or 11 instead of B.
e)
The 15's complement of a 4-digit hexadecimal number replaces each digit d with 15−d: it is bit inversion, since 15−d inverts the 4 bits of d. The 16's complement adds 1 to the result and equals 164−x=65536−x. For 02D416: 15's complement, F−0,F−2,F−D,F−4, that is FD2B16; plus 1, FD2C16. Check: 02D416=2(256)+13(16)+4=724, 65536−724=64812, and FD2C16=15(4096)+13(256)+2(16)+12=61440+3328+32+12=64812. Subtraction by addition: 1A7B16+FD2C16. B+C=23=16+7, write 7, carry 1; 7+2+1=10, write A; A+D=23, write 7, carry 1; 1+F+1=17=16+1, write 1, carry 1. We get 117A716; discard the carry out, and 17A716 remains. Check: 1A7B16=6779, 6779−724=6055, and 17A716=4096+7(256)+10(16)+7=6055. Link with two's complement: 4 hexadecimal digits are 16 bits, and FD2C16 is exactly the pattern of −724 in two's complement on 16 bits; the 16's complement is not another operation, it is two's complement written in base 16, four bits at a time. Signed range: from 800016=−32768 to 7FFF16=32767. A number is negative when its leading digit is 8 or more, because that digit contains the most significant bit; so FD2C16 read as signed is 64812−65536=−724.
f)
B0516−4C916. Ones: 5<9, borrow 16, 5+16−9=12, write C, and the sixteens digit must go down by 1; it is 0, so borrow from the 256s, B becomes A, and the sixteens become 16−1=15=F. Sixteens: F−C=15−12=3. 256s column: A−4=6. Result 63C16. Check: B0516=2821, 4C916=1225, difference 1596, and 63C16=6(256)+3(16)+12=1596. 10.416−7.C16: sixteenths 4<C, borrow, 4+16−12=8, and the ones, which are 0, borrow from the 1 on the left to become F; ones F−7=8; the leading 1 has become 0. Result 8.816. Check: 16.25−7.75=8.5=8+168. A borrow is worth 16, and a cascading borrow through a zero leaves an F behind it, as it leaves a 9 in decimal and a 7 in octal.
g)
2A16×B16: A×B=10×11=110=6(16)+14, write E and carry 6; 2×B+6=28=16+12, write C, carry 1, written in front. Result 1CE16; check 42×11=462=256+12(16)+14. Note the carry of 6: in base 16, a multiplication carry can go up to 14, which throws off anyone who only ever carries 1 out of habit. 1F16×3C16: by C, F×C=180=11(16)+4, write 4, carry 11; 1×C+11=23=16+7, write 7, carry 1, row 17416. By 3, shifted: F×3=45=2(16)+13, write D, carry 2; 1×3+2=5, row 5D016. Sum 17416+5D016: 4+0=4; 7+D=20=16+4, write 4, carry 1; 1+5+1=7. Result 74416; check 31×60=1860=7(256)+4(16)+4. 4.816×2.416: compute 4816×2416, then put back two fractional digits. By 4: 8×4=32=2(16)+0, write 0, carry 2; 4×4+2=18=16+2, write 2, carry 1, row 12016. By 2, shifted: 8×2=16, write 0, carry 1; 4×2+1=9, row 90016. Sum A2016, so A.2016=A.216. Check: 4.5×2.25=10.125=10+162.
h)
1000=16(62)+8, 62=16(3)+14, 3=16(0)+3, so 1000=3E816; and 255=FF16, written 0FF16 to line up. Subtraction 3E816−0FF16: ones 8<F, borrow, 8+16−15=9, and E becomes D; sixteens D<F, borrow, 13+16−15=14=E, and 3 becomes 2; 2−0=2. Result 2E916; back: 2(256)+14(16)+9=512+224+9=745=1000−255. Then 12.75=C.C16, since 12=C and 0.75=1612, and 2.5=2.816 since 0.5=168. Compute CC16×2816. By 8: C×8=96=6(16)+0, write 0, carry 6; C×8+6=102=6(16)+6, write 6, carry 6, row 66016. By 2, shifted: C×2=24=16+8, write 8, carry 1; C×2+1=25=16+9, write 9, carry 1, row 198016. Sum 66016+198016: 0+0=0; 6+8=14=E; 6+9=15=F; 0+1=1. Result 1FE016, and with two fractional digits 1F.E016=1F.E16. Back: 16+15+1614=31.875, and 12.75×2.5=31.875. The loop is closed: when the round trip comes out right, the conversion and the long calculation are validated in one go; when it does not, the error is in one of the two, and it is quickly located by rechecking the two conversions first.
Exercise 7: Overflow: when the result no longer fits
An overflow occurs when the exact result of an operation falls outside the representable range. The machine does not stop: it returns the truncated pattern, which is wrong. You therefore have to be able to DETECT the situation, and not confuse the carry out, which concerns unsigned arithmetic, with overflow, which concerns signed arithmetic.
a) With 8-bit signed integers, compute 100+50. What does the machine return?
b) State the rule that detects a signed overflow from the signs of the operands and of the result.
c) With 8-bit unsigned integers, compute 200+100. What does the machine return?
d) Does (−100)+(−50) overflow with 8-bit signed integers?
e) Can 100+(−50) overflow with 8-bit signed integers? Justify without computing.
Show the solution
Answers
a)The machine returns −106: overflow, since 150>127
b)Signed overflow if and only if both operands have the same sign and the result the opposite sign
c)The machine keeps 44 and raises the carry out: unsigned carry, not signed overflow
d)Yes: −150<−128, the pattern obtained is 106
e)No: opposite signs, the sum lies between −50 and 100
a)
100=01100100 and 50=00110010. The addition gives 10010110. The most significant bit is 1: read as signed, the result is 150−256=−106. Adding two positive numbers gives a negative one: that is an overflow. The exact value, 150, exceeds the ceiling 127, and the two's complement wheel shows why: moving 50 steps forward from 100, you cross the boundary between 127 and −128.
b)
Rule: a signed overflow occurs exactly when both operands have the SAME sign and the result has the opposite sign. Two numbers of opposite signs can never overflow, since their sum lies between the two. The processor implements this rule with an XOR between the carry into and the carry out of the most significant bit, which gives the same verdict.
c)
200+100=300, but the unsigned ceiling on 8 bits is 255. The machine keeps 300−256=44 and raises the carry out. The pattern kept is 00101100. Here there is no signed overflow in the sense of rule b): there is an unsigned carry. The two flags, carry and overflow, are computed at the same time by the processor, and it is the program that chooses which one to look at, according to the declared type of the variables.
d)
−100 and −50 have the same sign, and their exact sum −150 is below the floor −128: there is an overflow. The pattern obtained corresponds to −150+256=106, a positive number. The rule is confirmed: two negatives giving a positive.
e)
No. The operands have opposite signs, so their sum lies between −50 and 100, that is, strictly inside the range [−128,127]. This is a bounding argument, not a calculation: the sum of a positive and a negative number always lies between the two, so inside the range as soon as both operands are. A signed addition overflow can therefore always be detected by looking at the signs alone.
Part B: problems and reasoning (/50)
Exercise 8: Hexadecimal, masks and bitwise operations
Hexadecimal is not a base for computing: it is a compact way of writing binary. One hexadecimal digit is exactly 4 bits, one octal digit exactly 3 bits, which makes the conversions immediate by grouping, starting from the RIGHT. Bitwise operations, for their part, act on each position independently, with no carry at all.
a) Convert 10111110111011112 to hexadecimal, then to octal.
b) AND denotes the bitwise conjunction. What is B616 AND 0F16? And B616 AND F016?
c) Which operation forces bit 2 to 1 without touching the others? Which operation inverts it?
d) What is 10112 shifted 3 positions to the left, then 2 positions to the right?
e) How can you test whether an integer is even with a single bitwise operation?
f) Why is the binary to octal conversion done in groups of 3 and not 4?
Show the solution
Answers
a)BEEF16=1373578=48879
b)6 and B016=176, whose sum gives back 182
c)OR with 00000100 to set, XOR with the same mask to toggle
d)88 then 22
e)n AND 1 equals 0
f)Because 8=23: one octal digit is 3 bits, one hexadecimal digit 4
a)
Groups of 4 from the right: 1011111011101111, that is B,E,E,F: the number is written BEEF16. Check with the weights: 11(4096)+14(256)+14(16)+15=45056+3584+224+15=48879. For octal, split the SAME binary again into groups of 3 from the right, padding on the left with a zero: 1011111011101111, that is 1373578. Check: 1(32768)+3(4096)+7(512)+3(64)+5(8)+7=48879. The grouping must start from the right; starting from the left is the most frequent error, and it shifts everything.
b)
B616=101101102=182. The mask 0F=00001111 keeps the 4 low-order bits and clears the others: the result is 00000110=6. The mask F0=11110000 keeps the 4 high-order bits: the result is 10110000=B016=176. Check: 176+6=182; the two halves rebuild the byte. An AND is always used to CLEAR bits.
c)
To force a bit to 1 without touching the others, OR it with a mask that has a 1 only in that position: here OR00000100. To invert that single bit, XOR it with the same mask, since x⊕1=x and x⊕0=x. Three roles to remember: AND to clear, OR to set, XOR to toggle.
d)
10112=11. Shifted 3 positions to the left: 10110002=88, that is 11×23. That result shifted 2 positions to the right gives 101102=22, that is 88÷4. Careful: the right shift is an INTEGER division; the bits pushed out are lost, and 11 shifted right by 1 position gives 5, not 5.5.
e)
An integer is even if and only if its bit 0 is 0, so the test reads: n AND 1 equals 0. One operation, against a division and a remainder for the test nmod2=0. It is the classic optimization, and it remains correct for negative integers in two's complement, since bit 0 keeps the same meaning there.
f)
Because a base-b digit encodes exactly log2b bits: 16=24 gives 4 bits per hexadecimal digit, and 8=23 gives 3 bits per octal digit. The grouping works only because the base is a power of 2; there is no similar grouping toward base 10, and that is why the binary to decimal conversion requires divisions or weights.
Exercise 9: Computer codes: ASCII, BCD, Gray and parity
A code is not a base: it is a convention that associates a bit pattern with a symbol or a digit. The same pattern 01000001 means 65, or the letter A, or anything else, depending on the code applied. A bit pattern never carries its interpretation with it.
a) The letter A is 65 in ASCII. Write its pattern on 8 bits. The letter a is 97: what is the difference, and where does it show in the pattern?
b) Write 47 in BCD, then in pure binary. Compare the number of bits used.
c) The 3-bit Gray code is 000,001,011,010,110,111,101,100. What property does it satisfy? Give the conversion rule from binary.
d) The 7-bit word 1011011 is protected by an even parity bit. Which bit is added?
e) Does this code detect two simultaneous errors? Does it correct an error?
Show the solution
Answers
a)A is 01000001, a is 01100001: only bit 5 changes, hence the gap of 32
b)01000111 on 8 bits in BCD, 1011112 on 6 bits in pure binary
c)Only one bit changes between two consecutive codes; Gray bit k is the XOR of binary bits k and k+1
d)The parity bit is 1, the transmitted word is 10110111
e)It detects a single error, not two errors, and corrects nothing
a)
65=64+1, so A is written 01000001. And 97=64+32+1, so a is written 01100001. The difference is 32=25: the only bit that changes is bit 5. Going from an uppercase letter to its lowercase therefore amounts to forcing that bit to 1, and the reverse to clearing it. That is why converting to lowercase was historically coded as a simple OR with 00100000, with no table at all.
b)
In BCD, each decimal digit is encoded separately on 4 bits: the 4 becomes 0100, the 7 becomes 0111, so 47 is written 01000111, that is, 8 bits. In pure binary, 47=32+8+4+2+1=1011112, that is, 6 bits. BCD wastes space, since it uses only 10 of the 16 patterns of each nibble, but it makes display immediate, digit by digit. It is still found in displays, clocks and some financial formats, where exact conversion to decimal matters more than compactness.
c)
Two consecutive codes differ in only one bit, including between the last and the first. The conversion rule: bit k of the Gray code is the XOR of bit k and bit k+1 of the binary numeral. For example 5=1012 gives a first bit 1⊕0=1, a second 0⊕1=1, a third 1⊕0=1, that is 111, which is indeed the sixth word of the list. The benefit is physical: on a position sensor, if two bits changed at the same time, a slight timing offset between them would produce an absurd intermediate value. With Gray code, only one bit is ever in transition.
d)
The word 1011011 contains five 1s, an odd number. For the total to be even, the parity bit is 1, and the transmitted word becomes 10110111, which contains six 1s. Check on reception: count the 1s again; if there is an odd number of them, an error has occurred.
e)
It detects any error affecting an ODD number of bits, so a single error, but not two simultaneous errors: two flipped bits leave the parity unchanged and the error goes unnoticed. And it corrects nothing, since it only signals that an error exists, without saying where. Correcting requires more redundancy, for example a Hamming code, which adds several check bits placed so as to point to the position of the faulty bit.
Exercise 10: Five statements to correct
Each of the following five statements is FALSE. Say why and give the correct statement.
1) “In binary, appending a 0 on the right multiplies the number by 10.”
2) “On 8 bits, two's complement represents the integers from −127 to +127.”
3) “The pattern 11111111 is −1.”
4) “A byte is written with four hexadecimal digits.”
5) “With enough bits, 0.1 can eventually be written exactly in binary.”
Show the solution
Answers
1)FALSE: the base is 2, so the factor is 2. 1012=5 becomes 10102=10
2)FALSE: the range is [−128,127], that is [−2n−1,2n−1−1]
3)FALSE: −1 as signed, 255 as unsigned. The type is set by the program, not by the memory
4)FALSE: a byte is written with TWO hexadecimal digits, from 00 to FF
5)FALSE: 0.1 has no terminating binary expansion; the factor 5 in the denominator rules it out
1)
FALSE. Appending a zero on the right multiplies by the BASE, and the base is 2. Counterexample: 1012=5 becomes 10102=10, twice as much, not ten times as much. Correct statement: in base b, appending a zero on the right multiplies by b; in binary, by 2, and k zeros multiply by 2k.
2)
FALSE. The range is −128 to +127: it is asymmetric, because zero uses up a pattern on the positive side. Counting the patterns is enough to see it: 128 patterns for the negative numbers, 128 for zero and the positive numbers. Correct statement: on n bits, two's complement covers [−2n−1,2n−1−1].
3)
FALSE. The pattern does not carry its interpretation: 11111111 is −1 if it is read as a signed integer on 8 bits, but 255 if it is read as an unsigned integer. It means something else again if it is read as a character or as part of a floating-point number. Correct statement: the value of a pattern depends on the declared type, and it is the program, not the memory, that sets that type.
4)
FALSE. One hexadecimal digit is 4 bits, so an 8-bit byte is written with exactly TWO hexadecimal digits, from 00 to FF. Four hexadecimal digits describe 16 bits, that is, two bytes. Correct statement: n bits require n/4 hexadecimal digits, rounded up.
5)
FALSE. 0.1=101 and 10=2×5 contains the factor 5. A number has a terminating binary expansion only if its reduced denominator is a power of 2: the expansion of 0.1 is repeating, and adding bits only pushes the rounding further back. Correct statement: 0.1 has no terminating binary expansion, whatever the number of bits; that is why 0.1+0.2 is not exactly 0.3 on a computer.
Exercise 11: Problem: colours, memory and the size of an image
A screen colour is written in hexadecimal in the form #RRGGBB: two hexadecimal digits per component, red, green and blue, each component taking up one byte. A raster image stores one such colour per pixel.
a) Break down the colour #3C78D8 into its three decimal components.
b) How many distinct colours does this encoding allow?
c) An address bus has 16 lines. How many bytes can be addressed?
d) How much space does an image of 800 by 600 pixels in 24-bit colour take, in bytes and then in mebibytes?
e) Is the same 16-line bus enough to address this image? How many lines would be needed?
f) Is the colour #FFFFFF white or black? And #000000?
Show the solution
Answers
a)(60,120,216)
b)2563=224=16777216 colours
c)216=65536 bytes, that is 64 KiB
d)480000 pixels, 1440000 bytes, about 1.37 MiB
e)No: 21 lines are needed, since 220<1440000≤221
f)#FFFFFF is white, #000000 black: the synthesis of a screen is additive
a)
Split into three pairs: 3C, 78, D8. Red: 3(16)+12=60. Green: 7(16)+8=120. Blue: 13(16)+8=216. The colour is therefore (60,120,216), a strong blue, as the dominant blue component confirms.
b)
Each component takes 256 values, and the three are independent: 2563=224=16777216 colours. That is the famous 16 million colours, and the calculation is done by adding the bits, 8+8+8=24, rather than multiplying 256 three times.
c)
With 16 address lines, you form 216=65536 distinct addresses, that is, 64 kibibytes if each address designates one byte. Each extra line doubles the addressable capacity: it is a doubling, not an addition, and that is why moving from 32-bit to 64-bit addressing did not double the limit but put it out of reach.
d)
The image has 800×600=480000 pixels, at 3 bytes each: 1440000 bytes. Since a mebibyte is 220=1048576 bytes, that makes 1440000/1048576≈1.37 MiB. Order-of-magnitude check: half a million pixels at 3 bytes is about one and a half million bytes, so a little more than one mebibyte.
e)
No: 65536 addresses are not enough for 1440000 bytes. You need n such that 2n≥1440000. Since 220=1048576 is too small and 221=2097152 is enough, 21 address lines are needed. The reasoning brackets the value between two powers of 2, never by division.
f)
#FFFFFF sets all three components to their maximum, 255: it is white, the sum of the three lights. #000000 sets them to zero: no light emitted, it is black. The synthesis is additive because a screen emits light; on paper, ink absorbs and the logic is reversed, which explains why white there is the absence of ink.
Exercise 12: Problem: the IEEE 754 standard in single precision
A single-precision floating-point number takes up 32 bits: 1 sign bit, 8 exponent bits with a bias of 127, and 23 mantissa bits. The number is written (−1)s×1.m×2e−127: the leading 1 is not stored, since it is always there after normalization.
a) Write 6.25 in binary.
b) Normalize this numeral in the form 1.m×2k.
c) Compute the biased exponent, then give the 32 bits of −6.25.
d) Write these 32 bits in hexadecimal.
e) Up to which integer are all the integers represented exactly in single precision?
f) Are two neighbouring floating-point numbers separated by a constant gap?
f)No: the gap is 2−23×2k, it grows with the order of magnitude
a)
Integer part: 6=1102. Fractional part: 0.25=2−2, so 01 after the binary point. Hence 6.25=110.012. Check: 4+2+0.25=6.25.
b)
Move the binary point two positions to the left, which is compensated by a factor 22: 110.012=1.10012×22. Check: 1.10012=1+0.5+0.0625=1.5625, and 1.5625×4=6.25. Normalization requires exactly one 1 before the point, which makes the representation unique and makes it possible not to store that 1.
c)
The actual exponent is 2, so the stored exponent is 2+127=129=100000012. The sign is negative, so s=1. The mantissa is the part after the point, 1001, padded with zeros to 23 bits. The 32 bits are: 11000000110010000000000000000000. Numerical check: read as an unsigned integer, this pattern is 231+129×223+222+219=3234332672.
d)
Group the 32 bits in fours from the left, which is legitimate since 32 is a multiple of 4: 11000000110010000000000000000000, that is C0C8000016. Check: C0C80000 is indeed 3234332672, the same value as in the previous question.
e)
The mantissa has 23 stored bits plus the implicit 1, that is, 24 significant bits. All the integers up to 224=16777216 are therefore written exactly. Beyond that, only every other integer can be represented, then one in four, and so on. That is why a seconds counter or an identifier stored in single precision goes wrong from about 17 million on, without the slightest error message.
f)
No. The gap between two consecutive floats is 2−23×2k: it depends on the exponent, and so on the order of magnitude of the number. Near 1, the gap is about 10−7; near 106, it is about 0.06. Floats are tightly packed near zero and more and more spread out as you move away from it, exactly like the marks on a logarithmic scale. Practical consequence: adding a small number to a large one may change nothing at all, which makes a sum depend on the order of its terms.
Something missing from this set?A type of exercise your teacher gives, a problem you are stuck on, a mistake you spotted: tell me, I read every request.
Sending goes through your free space: that is how I can answer you and tell you when the exercise is added. An email is enough, no password. Create your space.
Rather not create an account? Write to me directly.
Looking for a computer science math tutor in Montreal?
Get in touch for a first session. With a B.Sc. in computer science from McGill and an M.Sc. in applied computer science from Concordia, I work through number systems on what actually breaks in real programs: silent overflows and floating-point comparisons.