 Again, we care about binary because it naturally allows us to represent numbers as bits, but you may be wondering why I bothered introducing octal and hex. Well, aside from helping to illustrate the concept of number bases other than ten, hex and octal have a special relationship with binary because two, eight, and sixteen are all powers of two. It works out that when one number base is a power of the other, such as eight is a power of two, conversions between those two number bases can be done without doing any arithmetic at all, making the conversions extremely easy to do in your head. These easy conversions help mitigate the practical problem of dealing with binary that binary numbers are quite verbose. As we saw, when we expressed even small quantities in binary, we used many digits to express even small quantities, making it inconvenient to put binary numbers in writing. The solution is not to write out binary numbers at all, but instead use their octal or hex equivalents as stand-ins. Because the mental conversion is so simple, a person reading octal or hex can just translate the binary in their head. So let's say we wish to convert from octal to binary or vice versa. All we need to do is memorize which three binary digits correspond to one octal digit. The octal digit five, for instance, is equivalent to the binary digits one, zero, one. The octal digit two is equivalent to the binary digits zero, one, zero, and so forth. So if I have the octal number three, six, seven, three, I can convert it to do binary if I simply substitute the binary equivalent of each digit. Consulting our chart, octal three is equal to binary zero, one, one. Octal six is equivalent to binary one, one, zero. And octal seven is equivalent to the binary digits one, one, one. And that can just as easily go the other way. If I have binary one, one, zero, one, zero, one, one, zero, I first group the digits into threes starting from the right, adding leading zeros if necessary to get complete groups of threes. And then I simply translate each group of three binary digits into the corresponding octal digit. The same idea works with conversions between hex and binary. The only difference is that each hex digit corresponds to four binary digits, not three. So if I simply memorize the binary equivalence of each hex digit, then I can easily translate the hex seven E nine to binary one, one, one, one, one, zero, one, zero, zero, one. And I can just as easily translate binary one, one, zero, zero, one, zero, one, one, zero, one to hex three, two, D. Before finally explaining how exactly bits are used to represent numbers, let me explicitly establish a basic philosophical point. And that is that all meaning relies upon agreement. For instance, the fact that all English speakers picture approximately the same thing when they hear the word dog relies upon a natural and informal agreement that that is what the word dog refers to. The implication this has in computing is that when a program writes data to some place in memory, the only way that data has any meaning is if the thing which is going to read the data interprets the data consistently with the writer's intention. For instance, imagine I write 16 consecutive digits on a piece of paper. If it's my intention that the first seven digits are a phone number, while the remaining nine digits are a social security number, that meaning is not inherent in the numbers themselves. If I, the writer of these numbers, come back a week later to read them, but I've forgotten what I intended when I wrote them, then the meaning is lost. If, for whatever reason, when reading, I reverse the order, if I read the first digits as a social security number and the last digits as a phone number, then I end up misinterpreting the data. And unlike for data written on a piece of paper to be read by a human, anything I store in computer memory must be represented as bits, so I can't simply add text labels to explain what a chunk of bits is supposed to mean. Therefore, for any data I store, I have to be careful to remember exactly where I put it and what the data in that location is supposed to mean. With that all established, let's finally look at representing numbers as bits. We'll start with simple integers. An integer recall is basically any whole number, a number without a fractional component. Examples include 5,878, 0, negative 87, and 234. When we represent integers as bits, we do so in two basic forms, signed or unsigned. A signed representation can represent both positive and negative integers, but an unsigned representation can only represent one or the other, usually positive. An unsigned representation of a number is straightforward. All we do is store a decimal number as its binary equivalent. For example, we represent decimal 3 with the bits 1, 1, because that's the binary equivalent of 3. An important thing to note is that given some number of bits, there's a maximum number of possible different states for those bits. If we have one bit, we have two possible states. If we have two bits, we have four possible states. Three bits gives us eight possible states and so forth. For each additional bit, we have twice as many possible states. So the formula 2 to the nth, where n is the number of bits, gives us the total number of possible states. For numbers, this tells us how many different values can be represented by a certain number of bits, and generally also tells us the range of those values. For unsigned numbers, one bit can represent the range 0 to 1, two bits can represent 0 to 3, three bits can represent 0 to 7, and so forth. Notice the maximum value is always 1 less than 2 to the nth, because 0 itself is always one of the possible values. To represent signed integers, there are a few approaches for indicating the sign. Most obviously, we could use a sign bit, a bit set aside to designate the sign. For example, if I have eight bits and wish to represent a signed integer, and I wish to represent positive 3, it would look like this, but negative 3 would look like this. We simply use the most significant bit as a flag, which when set to 1 denotes a negative number. One's complement is an alternative scheme in which positive integers look the same, but to get the negative of a positive, we simply flip all of the bits. Notice then that the most significant bit still effectively indicates the sign. 2's complement is a slight variation on one's complement, in which we negate a number by flipping all the bits, but then add 1. This in fact works both ways. To get a positive from a negative, I do the same thing, I flip all the bits and add 1. Like say, if I want to negate negative 3 to get positive 3, I flip all the bits and add 1. Again, the most significant bit still effectively indicates the sign. You're probably wondering why anyone would want to use the one's complement or 2's complement forms. Well, it turns out that for reasons having to do with the details of circuit logic, processors can do arithmetic upon 2's complement form more efficiently than they can on the simple sign bit form. So 2's complement is the form most often actually used in computers, but there's one more form called XSN. The idea in XSN is that we pick some arbitrary positive integer to represent 0. Everything above this number will be positive, whereas everything below it will be negative. So for instance, if I want to represent positive 3 in XS8, I represent it as 11 because 11 is 8 plus 3. But if I wish to represent negative 3 in XS8, I represent it as 5 because 5 is 8 minus 3. Notice that in XS form, we don't have a sign bit. For another example, let's say we wish to represent positive 3 in XS42. Well then, we represent it as binary 45 because 45 is 42 plus 3. Likewise, to represent negative 3 in XS42, we represent it as 39 because 39 is 42 minus 3. The interesting thing about XS form is that the range of values isn't necessarily evenly split between positive and negative values. For instance, if we use XS8, then our negative range only goes down to negative 7. But if we use XS42, our negative range goes down to negative 41. For the other forms, the negative range simply depends upon how many bits we're using. For an 8-bit number with a sign bit, or in one's complement form, the range is going to be negative 127 to positive 127. Oddly, this is only 255 different values, not 256. What explains this is that in these forms, we effectively have two representations for 0, a positive 0 and a negative 0. In 2's complement form, however, we have only one representation of 0, and so the range goes from negative 128 to positive 127, which is one more negative value than we have positive. That's all there is to know about representing integers, but what about rational numbers? A rational number, recall, is a number that's expressed as the ratio between two integers, a numerator and a denominator. The rationals are actually a superset of the integers, that is, integers themselves are rational. For instance, 3 can be expressed as the ratio of 3 over 1, or other equivalent ratios like 6 over 2. Integers and rationals differ in one important property. Both integers and rationals stretch off into positive infinity and negative infinity, but between any two rational numbers, there's an infinite number of other rational numbers. This is not the case with integers. Between any two integers, there's a finite number of integers. The implication of this is that when we say you can represent a certain range of rational numbers, we don't mean you can represent every possible rational number in that range because you simply can't represent an infinite number of values unless you have an infinite number of bits, which of course we never do. Rational numbers are often not expressed as ratios, but rather as an integer component and a fractional component separated by what's called a radix point. This is called radix point notation. For instance, the ratio 3 over 4 is represented in radix point notation as 0.75. To understand radix point notation, we need to revise our definition of positional notation. Let's say we have the number 36.259. We can represent this as the sum of the individual digit places like so, which in turn is equivalent to the sum of each digit place multiplied times sum power of 10, the number base. What's new here is that the digit places to the right of the radix point have negative exponents, whereas the digits to the left of the radix point are multiplied by the number base raised to an exponent that increases starting from 0, the digits to the right of the radix point are multiplied by the number base raised to an exponent that decreases starting from negative 1. For instance, here's octal 6, 2.732, and here's binary 1, 0.111. Notice that, say, the second digit to the right in binary represents 1 over 4, not 1 over 100, as a dozen decimal. We're actually dealing with different fractions in these number bases other than 10. Another important thing to realize is that some rational numbers are finite, whereas others are not. A finite rational number is a rational number which can be represented in radix point notation using a finite number of digits. For instance, 3 over 4 can be represented as 0.75, negative 7 over 1 is finite because it can be represented as simply negative 7, and 138 over 20 is finite because it can be represented as 6.9. However, 1 over 3 is not finite because it would take, in fact, an infinite number of 3s to the right of the radix point to fully represent. If we wrote 0.3333333, that would just be an approximation. No matter how many 3s we write after the radix point, it would still just be an approximation. Now, it works out that all rational numbers are finite in some number base, even if they're not finite in a particular number base. For instance, 1 over 3. When we express this in radix point notation in decimal in base 10, it's not finite, but if we express it in base 3, it is finite. In base 3, 1 over 3 is simply 0.1. Conversely, the ratio 3 over 4 is finite in decimal, but in base 3 it is not. There's actually a relatively simple formula we can use to determine whether a ratio is finite in a particular number base. The rule is that if the denominator of a ratio is a product of a set of factors of the number base, not including the number base itself, each multiplied by some set of exponents, then that ratio is finite in that number base. For example, any ratio with a denominator of 40 is finite in decimal because 2 to the 3rd times 5 to the 1st is 40, and 2 and 5 are factors that produce 10, and 3 or 1 are both non-zero positive exponents. Now, in the case of octal hex and binary, the rule still applies, but 8, 16, and 2 are all powers of 2, and so their factors are all powers of 2. Because, say, 4 is just 2 to the 2nd, we can simplify the formula by lumping powers of 4 in with powers of 2. Consequently, the formula for finite denominators of finite rationals in octal hex and binary is simply 2 to some exponent. So, any rational with a power of 2 denominator is finite in octal hex and binary, but all other rationals are not. You'll also note that in decimal, the formula yields all powers of 2, so any rational with a power of 2 denominator is finite in decimal as well. We can observe, then, that all ratios which are finite in binary are also finite in decimal, but only some ratios which are finite in decimal are also finite in binary. The most straightforward way to represent a rational number as bits is to do so as two separate integers, one for the numerator, one for the denominator. This is what it would look like if you wished to represent 3 over 4 using 8 bits for the numerator and 8 bits for the denominator. And this is how you would represent negative 7 over 13, again, if you were using 8 bits for the numerator and 8 bits for the denominator. This scheme is perfectly workable, but it is relatively costly performance-wise to do arithmetic upon rationals in this form. A more performant alternative is the computing equivalent of radix point notation, which we call fixed point. In fixed point, we reserve some number of bits to represent the integer component, that is, the digits to the left of the radix point, and we reserve some number of bits to represent the fractional component, the digits to the right of the radix point. So, for instance, the ratio 57 over 8, when expressed as binary in radix point, is 111.001. If we use 8 bits to represent the integer component and 8 bits to represent the fraction component, then this is the fixed point representation. While fixed point makes arithmetic more efficient compared to rationals represented as two integers, we just established that many ratios aren't finite when expressed as binary in radix point notation. In fact, many commonly occurring ratios, such as 1 over 10 or 1 over 9 or actually any ratio in which the denominator is not a power of 2, those values cannot be expressed fully in binary radix point, and so cannot be expressed fully in fixed point. The best we can do is approximate those values by rounding or simply truncating past a certain digit. This is not to say that the approach of representing a ratio as its numerator and denominator is perfect. We're always dealing with a finite number of bits, so there are always values which we can't fully represent. The difference is that the values we can't represent in fixed point tend to be more surprising if you're not cognizant of the issue with finite rationals. You may be familiar from science class with what's called scientific notation or sometimes engineering notation. In scientific notation, we express a value as a radix point number multiplied by the number base raised to an exponent. The radix point number is called the mantisa, or significant, and should have only one digit left of the radix point. The exponent, meanwhile, should be whatever is required to make this significant have only one digit to the left of the radix point. So, for instance, the value 362.354 expressed in scientific notation has a significant 3.62354 multiplied by 10 raised to the second power. When you multiply a number by its number base raised to the second power, the radix point effectively moves two places over to the right. Conversely, when you multiply a number by its number base raised to a negative power, the radix point effectively moves that number of places to the left. So, 0.00736234 expressed in scientific notation is 7.36234 multiplied by 10 raised to the negative third, because the radix point effectively moves three places over to the left. In computing, we use an analog of scientific notation called floating point. In floating point, we represent a rational number as a significant and an exponent, where the significant is represented in binary, and the exponent is the power to which we are raising two. Let's say we wish to represent 21 over 2 in floating point. 21 over 2 expressed in binary radix point is 1010.1. Expressed in scientific notation, this becomes 1.0101 multiplied by 2 to the third, and so in floating point, we store the significant 1.0101 and the exponent 3. Assuming we're using 8 bits for the significant and 8 bits for the exponent, it would look like this. The significant gets transcribed into its bits, whereas the exponent is expressed simply as an integer. As a final exercise, let's try and express this decimal number in floating point. First, we need to convert it to binary. The integer 6 is the sum of 2 and 4, so we know that 6 in binary is 110. To convert the fractional component, it's actually easiest if we first express it as a ratio. So 0.75 is equal to 3 over 4. 3 over 4 is the sum of 2 to the negative first and 2 to the negative second, which are 1 over 2 and 1 over 4 respectively. So the digits to the right of the radix point are 11. Now to get our significant in exponent, we move the radix point two places to the left by factoring out 2 to the second. So our significant is 1.101, and our exponent is 2. Represented with 8 bits for each, we get 1.101, 1.000, and 0.000, 0.010. The way we've presented floating point so far is a workable scheme, but not the way floating point is actually done in practice. The IEEE, an international standards body, prescribes the most common formats for floating point, including the most used 32-bit, 64-bit, and 80-bit formats. These standards prescribe exactly how to use the bits to represent a significant and an exponent. These standards also allow for representing a few special values, such as positive infinity and negative infinity. If you're interested in the details, you should read the Wikipedia article on these standards.