CIT 593 Intro to Computer Systems Lecture #2 (9/11/12) Decimal-to-Binary conversion Converting binary to decimal is pretty easy. What about going the other direction? That's a bit more complicated. Let's try to convert the decimal number 73 to binary. Before we do that, a few “sanity checks” about our answer: First, how many bits will it have? Well, we know that the largest 6-bit binary number is 26 – 1 = 63, so our answer must have seven bits, since the largest 7-bit number is 27 – 1 = 127, and 127 > 73 > 63. Also, we know that the last (“least significant”) bit will be 1. Why? Because 73 is odd. All of the other powers of 2 are even, except for 20 of course, so in the “ones” place we must have a 1. Okay, here goes. To do the conversion, we first divide 73 / 2 to get 36 with a remainder of 1. The remainder is what goes into our binary number: in this case, it's the rightmost bit. Which makes sense, because we said that bit should be 1 since 73 is odd. So now we have _ _ _ _ _ _ 1. Now we repeat. We divide 36 by 2 and get 18 with a remainder of 0. The 0 goes into the rightmost available spot, giving us _ _ _ _ _ 0 1. Now we divide 18 by 2 and get 9 with a remainder of 0. We put that remainder into the rightmost available spot, giving us _ _ _ _ 0 0 1. And so on: 9/2=4r1→___1001 4/2=2r0→__01001 2/2=1r0→_001001 1/2=0r1→1001001 Once we get 0 as our quotient, we're done! Can we check our work? Sure, we can calculate that 1001001 = (1 * 26) + (0 * 25) + (0 * 24) + (1 * 23) + (0 * 22) + (0 * 21) + (1 * 20) = 64 + 8 + 1 = 73. Hexadecimal Numbers Working with binary numbers can be complicated. Even the smallest three-digit decimal number takes seven bits to represent (think about it), and the smallest four-digit decimal number requires 10 bits. So when humans work with binary numbers, they often use hexadecimal, or base-16, numbers. In this case, there are sixteen digits: 0-9, and then A (which is ten in decimal), B (which is eleven in decimal), C (twelve), D (thirteen), E (fourteen), and F (fifteen). To understand the value represented by a hexadecimal number, you just multiply each digit by the appropriate power of 16. So 42 in hexadecimal represents (4 * 161) + (2 * 160) = 64 + 2 = 66 in decimal. And 3AB in hexadecimal represents (3 * 162) + (10 * 161) + (11 * 160) = 768 + 160 + 11 = 939. Usually, to represent a hexadecimal number, we put a lower case 'x' in front of it in order to make it clear whether it's hexadecimal or decimal. So “x42” is 66 in decimal (as shown above), but “42” is just plain old (decimal) 42. Signed Integers To represent sign (positive or negative) in decimal, we typically use + and -, of course. And nothing stops us from doing that in binary or hexadecimal or any other number system. However, in the context of the binary numbers used in the computer, we are limited to 1s and 0s, and thus must somehow use those to indicate sign. One way is to simply use a bit to represent sign. For instance, 0 can be positive and 1 can be negative. That is: 0110 would represent +6 1110 would represent -6 (instead of +14, as it would if it were an unsigned integer) This is known as sign-magnitude notation: the first bit is the sign, the rest is the magnitude. This is simple enough but has one obvious drawback. What is 0000? What is 1000? Hmmm... Another drawback is that sign-magnitude notation makes addition a little weird. When you add 0110 + 1110 (i.e., +6 + -6), you would expect to get zero. But what do you get? Not zero. So we want a system in which there is only one representation of zero, and also such that when you add a number to its negative, the sum is zero. This representation is called two's-complement. In two's-complement, the most significant bit still represents sign (0 is positive, 1 is negative) but the remaining bits only represent magnitude if the number is positive. So 0110 is still +6. But to figure out what -6 is, we need to do the following: • take its positive representation, i.e. 0110 • invert the bits, which would give us 1001 • add 1, which gives us 1010 This has the nice property that 0110 + 1010 = 10000, in which case we omit the first 1 (since we only have a four-bit number), giving us a sum of 0000, or zero. How about going the other way? What would 1101 represent? It's clearly negative, but what value does it represent? We can just do the same steps as above, but in the other order: • subtract 1, which gives us 1100 • invert the bits, which gives us 0011 • and we're done! That represents -3 We saw in sign-magnitude that 1000 represents zero. What does it represent in two's-complement? • subtract 1, which gives us 0111 • flip the bits, which gives us 1000 • and we're done! That represents -8 Note that -8 is the smallest number (“most negative”) that can be represented with a four-bit two'scomplement signed integer. Signed Arithmetic and Overflow Adding 2's-complement integers works just like adding unsigned integers, with one big exception. Because the most significant bit is used to represent the sign, we're pretty much limited to a fixed number of bits. For instance, when we add a five-bit 2's-complement number to another five-bit 2's complement number, we expect the sum to also be five bits, so that the most significant still represents the sign (and not a carry over from adding the next most significant bit). This can cause a problem. There is, of course, a limit to the number of values we can represent with five bits. The biggest number is 01111 = 15. The smallest number (“most negative”) is 10000 = -16. What it we add 8 and 9? We can't represent 8+9 = 17 with a five-bit 2's complement number. This is called overflow. Put simply, overflow occurs when you add two positive numbers and get a negative number; or when you add two negative numbers and get a positive number. For instance, if we add 8 and 9, we have: 0 1 0 0 0 + 0 1 0 0 1 ----------1 0 0 0 1 Uh-oh. What happened? Treating this as a five-bit two's-complement number, it looks like we got -15. Thus, this is considered overflow (note that if we treat it as a six-bit number, and stick a zero in front of it, it correctly represents +17, but there's nothing to indicate that we should do this). One last note: can you have overflow if you add a positive number and a negative number? No, because you end up going closer to zero, and not past the end of the positive/negative number ranges. Floating Point Numbers There are a few ways in which we can represent floating point values (i.e., numbers that have fractional parts) in binary. One is to use a decimal point (well... “binary point”?) between the digits. For instance, just as you have 12.345, you can conceivably have 1101.101. What does 1101.101 represent? Well, just as 12.345 represents (1*101) + (2*100) + (3*10-1) + (4*10-2) + (5*10-3), we can do the same in binary. In this case, 1101.101 represents (1*23) + (1*22) + (0*21) + (1*20) + (1*2-1) + (0*2-2) + (1*2-3) = 8 + 4 + 1 + 0.5 + 0.125 = 13.625. As with signed numbers, however, inside the computer we don't always have the luxury of things like decimal points, so we need some representation for floating point numbers. We'll start with the observation that, just as 12.345 can be written in scientific notation as 1.2345*101 we can also write 1101.101 as 1.101101*23. Here, we note that a number written in this notation would always start with a 1 (i.e., you wouldn't start it with a zero), and we say that the part of the number after the decimal point is the “fraction” and the power to which 2 is raised is the “exponent”. We also need something for the sign. Thus, we can assign certain bits in our floating point binary number to represent the sign, exponent, and fraction and we're all set. Of course, we need some standard for doing so. The IEEE defines the representation of a 32-bit signed floating point number N as follows: 1 8 23 S exponent fraction where N = (-1)S × 1.fraction × 2exponent-127 For example, consider the number: 1 10000010 11010000000000000000000 The most significant bit is S = 1. The next eight bits are the exponent, which is 10000010, or 128 + 2 = 130. The fraction part is the last 23 bits: 11010000000000000000000. If we consider that an unsigned int, that's a huge number, of course, but we're going to treat as our fraction. That is, the number is (-1)S × 1.fraction × 2exponent-127 = (-1)1 × 1.11010000000000000000000 × 2130-127 = (-1)1 × 1.11010000000000000000000 × 23 = -1 × 1110.10000000000000000000 = -1 × 14.5 = -14.5 Note that by having 8-bits for the exponent, but subtracting 127, we get a very big range for the exponent (-127 to 128), allowing us to represent really big and really small numbers. Also note that there is one big limitation: we cannot perfectly represent all irrational or even rational numbers with just 23 bits for the fraction. That's why you'll occasionally see weird behavior in Java and C (and any other language) when it comes to working with fractions.
© Copyright 2026 Paperzz