Start with a BUG

(Note: If you have no programming experience or just want to start with binary, you can skip this section and go straight to 1. Learn about the binary section.

A few years ago, on a project I was working on, a strange problem arose that could be abstracted from a piece of code that looked something like this:

i = 0
while i < 2:
    if i == 0.9:
        print(0.9)
    elif i == 1.2:
        print(1.2)
    elif i == 1.5:
        print(1.5)
    i += 0.1
Copy the code

Guess what this code will eventually print? Well, 1.2. This code only prints 1.2. That is, in this code, both I == 0.9 and I == 1.5 are false, so the print code in the following blocks is not executed.

This is confusing because the logic of this code is so simple that even novice programmers can see that there is nothing logically wrong with this code: I starts at 0 and +0.1 each time, I must have the values I == 0.9 and I == 1.5. This is logically clear and mathematically correct, and the code output is 1.2, which means the code must have passed 0.9, but why are 0.9 and 1.5 not output in our code?

In fact, if we change the code so that it prints the current value each time through the loop, we can see something:

# code
i = 0
while i < 2:
    print(i)
    i += 0.1

# the results
0
0.1
0.2
0.30000000000000004
0.4
0.5
0.6
0.7
0.7999999999999999
0.8999999999999999
0.9999999999999999
1.0999999999999999
1.2
1.3
1.4000000000000001
1.5000000000000002
1.6000000000000003
1.7000000000000004
1.8000000000000005
1.9000000000000006
Copy the code

See? It’s weird, right? This is my output in Python 3.6, if you are interested, try other languages to see if it is the same.

The results naturally raise the question:

Why is that?

All of this has to do with the subject of this article ———— binary.

0.30000000000000004 0.1.

In fact, the above problem is well-known throughout the computer world, it has a more familiar description: 0.1 + 0.2 = 0.30000000000000004. There’s even a website [Floating Point Math] that tallies 0.1 + 0.2 results in various languages. The root of the problem is the accuracy of floating point numbers in computers. In 1989, computer scientist William Kahan won the Turing Prize for his numerical analysis of floating point arithmetic. He was also the principal architect of the FLOATING point arithmetic standards IEEE 754 and IEEE 854.

So what’s going on with this so-called accuracy problem? Since this section is the introduction of the whole article, the focus of this article is on binary itself, so here is a few sentences to briefly explain the accuracy problem. To put it simply:

All computer operations, storage, are carried out in binary, binary can accurately represent integers, but can not accurately represent some fractions (decimals). So, what we see as 0.1 is actually stored in the computer is not the familiar 1/10, it’s just a very close approximation to 0.1, and this value, maybe 0.10000000000000001, May also be a 0.1000000000000000055511151231257827021181583404541015625, but it is only an approximation. By the same token, 0.2, 0.3, etc, the decimal is approximation, thus in the beginning of the code, we used to judge the 0.9, 0.9 and calculated by the program loop out is not the same, 0.9 in precision difference is we can’t see the figures, like the two above 0.1 approximation, and the difference when comparing numerical program, Is judged to be false, not equal, hence the program “BUG” seen at the beginning of this article.

So why can’t binary accurately represent certain decimals? And that’s what happens when you compute binary, but we’ll leave that for later.

After explaining the general cause of the accuracy problem, let’s go back to the code at the beginning of the article. Since the source of this BUG is a computer problem, is there any way to solve it in the code? Well, there is.

Many languages provide tools for high-precision calculations that can be used to solve the problem in this code. Using Python as an example, there is a library called Decimal in Python’s standard library that solves our problem perfectly. The code modified is as follows:

from decimal import Decimal

i = Decimal('0')
while i < Decimal('2') :if i == Decimal('0.9') :print(0.9)
    elif i == Decimal('1.2') :print(1.2)
    elif i == Decimal('1.5') :print(1.5)
    i += Decimal('0.1')
Copy the code

After that, 0.9, 1.2, and 1.5 can all be printed on the screen according to the code logic.

What if our language doesn’t have this convenient high-precision library? Here is another method:

epsilon = 0.01
i = 0
while i < 2:
    if abs(i - 0.9) < epsilon:
        print(0.9)
    elif abs(i - 1.2) < epsilon:
        print(1.2)
    elif abs(i - 1.5) < epsilon:
        print(1.5)
    i += 0.1
Copy the code

This method also fixes the BUG in this code. Those of you who are familiar with higher mathematics may have noticed that this method is actually borrowing from the definition of limits in higher numbers. Put it in this code to say that even though this “I” doesn’t really equal 0.9, it always has an accuracy that is infinitely close to 0.9 on a computer, so let’s set epsilon to be small enough that it’s at least smaller than the change in “I.” However, it is greater than the accuracy of the storage, so it can be used to judge whether I approaches 0.9. If it approaches, we believe that I can be regarded as 0.9 at this time.

1. Know binary

Having simply solved the above problems, let’s take a look at today’s hero, binary.

1.1 Carry counting system

The binary, octal, decimal, hexadecimal and so on that we usually refer to are essentially a way of counting. That is, the so-called base system is the carry counting system, the difference between different bases is only the difference in the way of carry.

In daily life, people use the decimal system, which consists of 0 to 9 digits, counting every ten into one. For an example of the count, we start from 00 (supplement ten 0), followed by the by, 01 until last, then the next number is 11 Numbers, beyond the decimal 10 limit, so we in the second place (count from the right, that is, 10) takes a, 1, bits to return to zero, finally formed 10. It is said that humans chose the decimal system because they have ten fingers, making it very convenient to do calculations. Is there any other base system used in the evolution of human civilization? Yes, binary, quintuple and even binary have all appeared in history. For example, in China, the common counting method of positive characters is a five-base system.

We know that inside computers, we use binary, that is, the numbers of zeros and ones, where every two goes into one. So why do computers use binary? The reason is similar to the human decimal system above, because binary most conforms to the binary logic of electronic components, namely high level and low level, or understood as on (on) and off (no). Binary is the same as decimal in counting, the rightmost digit is the lowest, the more left digit is higher, the only difference is “every two into one”. So for example, we start at 0, 00, then 01, and up here, binary and decimal numbers are the same, 0 and 1. But now we’ve already counted two numbers, so the next number of 1 should be 2, and there are only 0 and 1 in binary, so the next number of 01, the second digit (from right to left) goes one, becomes 1, and the first digit goes back to 0, and the combination is 10.

See, as mentioned above, binary and decimal counting is very similar, except that the whole counting process is exactly the same. In addition to these two, the other two commonly encountered base system, octal and hexadecimal, in the basic function of counting, the process is exactly the same as them. Even if we were to design a random base system, such as ternary or quad, they would still count in the way described above.

The other thing to notice in the above two base examples is that both binary and decimal numbers are changed to 10 after the first carry, but this 10 does not represent the same number in the two bases. Ten in decimal is what we normally know as ten, and ten in binary is two in decimal, or the third digit after zero when we count. By this rule, we can vaguely guess that if we use octal and hexadecimal numbers, their respective 10, the first carry number, should represent the decimal 8 and 16, respectively.

We seem to have caught a glimpse of how base conversion, especially other base conversion methods and rules to decimal, but how does this conversion work? Let’s move on.

2. Base conversion (integer)

2.1 Decimal Decomposition

Because we usually use the decimal and the Arabic numeral design itself also conforms to the characteristics of the decimal, so we in the years of osmosis, the entire digital thinking became the decimal thinking, unless specially trained, otherwise ordinary people related to digital operation, the brain is always in a decimal thought to carry out. Our brain has been trained to be a decimal computer, so to speak.

And that’s why it’s relatively easy to convert other base numbers into decimal numbers, and it’s consistent with our habits of thinking ———— convert something we’re not familiar with into something we’re familiar with.

Before we talk about base conversions, let’s take a look at the most familiar decimal notation.

We give an arbitrary decimal integer, such as 123, which we pronounce in Chinese as 123, which means that 123 is the sum of 100, 20 and 3. And that’s pretty obvious, because the hundreds place is 1, which is 1 x 100, the tens place is 2, which is 2 x 10, the ones place is 3, 3 x 1, and finally 1 x 100 + 2 x 10 + 3 x 1 is 123. Although we won’t be so 123 at ordinary times, because the number itself is already a decimal number can probe into the mind, but when we put 123 look at the number of ways, the whole process of it doesn’t make us any discomfort, because, one, ten, hundred, thousand, million, the decimal number we see everyday is so of, This combination is very natural.

Now that we’ve disassembled a decimal number, can we go one step further and express it in a mathematical formula?

Again, 123, if we look at 1 x 100 + 2 x 10 + 3 x 1 = 123, we see that this is a typical polynomial, 1, 2, 3 are coefficients, and 100, 10, 1 are exponents of 10, 10n10 to the n10n, so, 1×102+2×101+3×100=1231\times10^2+2\times10^1+3\times10^0=1231\102+2×101+3×100=123

More generally, we replace the coefficients of the polynomial with ana_nan, write the final result 123 with a capital S, and then change the order of the above equation slightly to get something like this: S = a1 + a2 + a3 x 102 x 101 x 100 S = a_1 \ times10 ^ 0 + a_2 \ times10 ^ 1 + a_3 \ times10 ^ 2 S = a1 + a2 + a3 x 102 x 101 x 100

So this is a standard decimal composition, and we started thinking: The coefficients of this polynomial are the numbers we see, and that makes sense, but the base of the exponent, why is 10? Many friends will certainly say: because it is decimal ah!

That’s right, because it’s decimal. If we look at 123 again, the first place is 3, and the ones place doesn’t carry, they’re all less than 10, so the exponent in the ones place is 10010 to the 0100. Then a second, ten, ten is 2, but all the Numbers are a bit on the ten after they carry, so when the number of non-zero on ten, the minimum number is 10, and become 20, carry on until ten to nine, ten, it’s the end of the, again, have to carry on the third (one hundred), as a result, The second exponent would naturally be 10110^1101, and the third exponent would be 10210^2102.

Those of you who are sensitive to programming may have noticed that the process of counting + carrying is like a multiple loop.

All numbers up to 1000 can be printed from 0 to 999
for third in range(10) :for second in range(10) :for first in range(10) :print(int('{0} {1} {2}'.format(third, second, first)))
Copy the code

2.2 Convert other bases to decimal

The point is, as we said earlier, the reason why the exponential part of the split decimal polynomial has a base of 10 is because we’re using decimal, but what about binary? What is this base? Could it be… 2! Let’s give it a try.

First, we take an arbitrary binary integer, such as 101, with a 1 in the first and third digits and a 0 in the middle. Let’s use our primitive notation to figure out what the number is.

Starting with 000, then 001,010, 011,000, 100,101, the last four numbers in decimal form are: 1,2,3,4,5, so 101 is actually a binary number of 5. Let’s do it with the polynomial we talked about, and see if the base is 5. 1×22+0×21+1×20=51\times2^2+0\times2^1+1\times2^0=51×22+0×21+1×20=5

It’s really 5! So the exponential base of this polynomial really is 2, and our guess seems to be correct, right? Be confident, take it away, our guess is correct, and if you’re interested, you can manually try other integer calculations.

So, we’ve successfully converted from binary to decimal… Wait, why am I so sure that this transformation is decimal? Isn’t that a little hasty? Why not some other base?

That’s a good question, and one I asked myself when I first encountered binary conversion computing. The answer to this question is simple: the ** polynomial is the same polynomial, and the result of the calculation depends on what base we are using. What does ** mean? In other words, since we are computing this polynomial in decimal, our results are also in decimal. In other words, if the above two examples were calculated using other bases, the resulting numbers would be the same as those in other bases. Of course, in binary 101, all numbers are less than or equal to 5, so the resulting 5 is also octal and hexadecimal.

The principle is fine, but in fact we can’t do this manually. There are all kinds of problems and pitfalls. For example, if we want to calculate the polynomial of decimal 123 in binary, we get something like this: 1×101010+10×10101+11×10100=? 1\times1010^{10}+10\times1010^1+11\times1010^0=? 1 + 10 x 10101 x 101010 x 10100 + 11 =?

Well, that’s right, we can’t do it ourselves, we have to use programming languages or other tools to do it:

s = int('1'.2) * int('1010'.2) * *int('10'.2) + int('10'.2) * int('1010'.2) * *int('1'.2) + int('11'.2) * int('1010'.2) * *int('0'.2)
print(s, bin(s)[2:)# the results
123.1111011
Copy the code

Python calculates this number for us, and it is 123, but it is written in decimal by default, so we use the binary conversion function bin() here to get the binary result 1111011.

For example, let’s calculate the polynomial expression for the decimal number 123 in octal: 1×122+2×121+3×120=? 1\times12^2+2\times12^1+3\times12^0=? 1 x 122 + 2 + 3 x 120 x 121 =?

This is a lot easier to look at than the binary one, because it looks like a decimal one. Of course, just like decimal, it’s not decimal, just octal. At this point, if we start counting subconsciously, we fall into the base trap again: we’re counting octal as a decimal number. 1×122+2×121+3×120=171 (×) 1×122+2×121+3×120=171 (×) 1×122+2×121+3×120=171 (×) 1×122+2×121+3×120=171 (×) 1×122+2×121+3×120=173 (√) 1\times12^2+2\times12^1+3\times12^0=173 (√) 1×122+2×121+3×120=173 (√)

The first expression above is the result of our direct calculation, which is octal in decimal, and the result is obviously wrong; The second expression is computed in octal notation, and the result 173 is the octal representation of 123. Although 171 is wrong, it is obvious that 171 is very close to the correct value 173, but only because the original number 123 is not large, and decimal and octal are relatively close, so the error is small. Even if we count octal the wrong way, we can get the correct answer, for example, the decimal integer 12, which has an octal number of 14, we can count octal in decimal: 1 + 2 x 120 x 121 = 141 \ times12 ^ 1 + 2 \ times12 ^ 0 = 121 + 2 x 141 x 120 = 14

It does turn out to be 14, which seems correct, but it’s just a coincidence of small integers.

Sum_ {I =1}^{n}a_ix^{I -1}∑ I =1naixi−1

In the above formula, n is the number of digits of the number, aia_iai is the number of each digit, that is, the coefficient of each term of the polynomial, xi−1x^{i-1}xi−1 is the exponential part, where XXX is the base number of the number, for example, in binary conversion, XXX is 2. The result calculated by this formula is the result of converting other base integers to decimal.

2.3 Converting from Decimal to Other Bases

In this paper, start from here, if no special circumstances, will be reduced or not on binary and decimal, hexadecimal outside, because once upon a time, we can found that different base count, calculate and other operations are very similar, just like the start of this chapter, they just carry a different way, behind so we can very easily extrapolate, Through some calculations and characteristics of binary, to calculate the case of other bases.

Return to the text. Since our calculations and habits are based on the decimal system, manual conversion of any base to other than the decimal system can only be done through the decimal system unless we are proficient in the calculations of other bases. So how do you convert decimal to other bases correctly?

Let’s go back to the previous paragraph. When converting integers from other bases to decimal, we mainly multiply and add them. Assuming that converting integers from decimal to other bases is the reverse of the above operation, does this mean that we need to use division and subtraction to convert an integer from decimal to other bases?

Yes, you guessed it.

I don’t know if you’ve noticed, but when we dismantled the decimal number 123 in the previous article, we immediately decomposed the whole number into polynomials multiplying by 1, 10, 100 and their coefficients. In fact, the so-called inverse operation we will discuss in this section is very similar to this unpacking principle.

Let’s take the decimal number 123 again, and break it up into decimal digits one by one. How do we do that? Since it’s decimal, let’s divide 123 by 10 to see what we get: 123÷10=12…… 3123\div10=12…… 3123 present 10 = 12… 3

So 12 has a remainder of 3, and this remainder, 3, is our ones place. Now, 123 loses the ones place, it becomes 12, which is what you get when you split the ones place. In the same way, we can divide 2 of 12 again: 12÷10=1…… 212\div10=1…… 212 present 10 = 1… 2

So we have another 2,123 in the tens place and after this unpacking, we are left with only 1 in the hundreds place. We then unpack: 1÷10=0…… 11\div10=0…… 11 present 10 = 0… 1

Only look at the three the remainder of a formula, we passed the operation three times, in order to get the 3, 2, 1, 3 is a bit due to the operation for the first time the remainder of the remainder, so it should be in the end, we are in the form of a queue (first in first out), the number of these three together, will become 123, namely before dismantling the original number. Compared with the violent decomposition of the compact in Chapter 2.1, is this method of disassembly much gentler and more mathematical?

Why can you disassemble it like this?

The principle is obvious: ** because we want to get decimal, we divide by 10. ** In other words, this disassembling method conforms to the decimal counting method, i.e., every ten is one. One into ten means that this whole number, if it has entered several places, must have experienced several tens, and there are several tens in the number.

For example, 13, which is carried from 9 to 10 and then counted to 13, has only carried once, has not carried a second time, so there is only one 10 in this number. What about our number 123? It carried 12 times in the count, and the last 3 was the count after the 12th carry, so when we divide by 10 the first time, we get 12, and we split out the remainder of 3. The 12 rounds can be subdivided into n tens, so we do division and subtraction again, and we end up with 0, which means there are no more 10s in this number.

Remember the Chinese counting method of positive characters mentioned in chapter 1 of **? When we finish counting the results, we usually directly count the number of positive, multiply the number of positive by 5, and then add the number of strokes that do not constitute positive words in the end. For example, if we count 21 positives and one one is left, the result is: 21×5+1=10621\times5+1=10621×5+1=106.

Yi? Isn’t this the inverse of the first expression when we split 123? 5 is the divisor, 1 is the remainder, and 21 is the result. So with 123, can we take this 21 and divide it by 5? 21 members present 5 = 4… 121\div5=4…… 121 present 5 = 4… 1 4 present 5 = 0… 44\div5=0…… 44 members present 5 = 0… 4

Once again, we have three remainers 1, 1, and 4, so we combine them to form a new integer: 411. Is this the same integer as 106 in pentadecimal? 4×52+1×51+1×50=1064\times5^2+1\times5^1+1\times5^0=1064×52+1×51+1×50=106

Exactly!

Well, we have found the algorithm and rule of converting decimal to other bases through the decomposition of decimal, and then it is binary.

Given a positive decimal integer 13, we divide it by 2:13÷2=6…… 113\div2=6…… 113 present 2 = 6… 1 6 present 2 = 3… 06\div2=3…… 06 present 2 = 3… 0 3 present 2 = 1… 13\div2=1…… 13 members present 2 = 1… 1 1 present 2 = 0… 11\div2=0…… 11 present 2 = 0… 1

1×23+1×22+0×21+1×20=131\times2^3+1\times2^2+0\times2^1+1\times2^0=131×23+1×22+0×21+1×20=13

It was 13. As a result, we have fully mastered how to convert decimal integers into other bases. If you are interested, you can try octal, hexadecimal, etc., which are not mentioned here. As mentioned above, the principle is the same, and the calculation method is only different in the way of carrying.

3. Decimal conversion

I didn’t write this chapter when I was due for the first time, because it was too much and I planned to save decimals for the next one. Later, I decided to write the conversion of decimals at the end of this article, in order to echo the chapter 0.**.

3.1 Converting to decimal system

Before we look at the conversion of other bases to decimal, we will follow the convention of parsing decimal numbers themselves and then deducing the conversion of other bases.

Let’s take a decimal number, 0.123. Now, given the whole number deduction, we can just break 0.123 down. Remember the first disassembly of 123? 123 is made up of one 100, two 10s and three ones, which in decimal terms are 1×1021\times10^21×102, 2×1012\times10^12×101, and 3×1003\times10^03×100, respectively. We notice that in the ones place, the power of 10 has decreased from 2 to 0 in the hundreds place, so we can guess that if we move further to the right and get to the decimal place, the exponent n decreases further and becomes -1, -2, and so on. In other words, the decimal part of 0.123 can be written as: 1 x 2 x 10-10-1 + 2 + 3 x 0.1 x 10-3 = 1 + 2 + 3 x 0.001 x 0.01 = 0.1231 \ times10 ^ {1} + 2 \ times10 ^ {2} + 3 \ times10 ^ \ {3} = 1 + 2 + 3 \ \ times0.01 ti times0.1 Mes0.001 = 0.1231 x 2 x 10-10-1 + 2 + 3 * 10-3 = 1 * 0.1 + 0.01 + 2 x 3 x 0.001 = 0.123

The decimal calculation deduced from this is very intuitive. If we want to convert a binary to decimal, do we only need to replace all the 10’s in the above formula with 2’s? For example, here is a binary decimal number 0.101, which, according to our deduction, should be converted to decimal: 1 x 2-1 + 0 + 1 x 2 x 2-2-3 = 12 + 0 + 18 = 0.5 + 0.125 = 0.6251 \ times2 ^ {1} + 0 \ times2 ^ {2} + 1 \ times2 ^ {3} = \ frac {1} {2} + 0 + \ frac {1} {8} = 0.5 + 0.125 = 0.6251 x 2-1 + 0 + 1 x 2 x 2-2-3 = 21 + 0 + 81 = 0.5 + 0.125 = 0.625

Since there is no built-in Python function for converting a binary decimal directly to decimal, we can find an online conversion tool and try it out for ourselves. We will find that the formula above is true. In other words, the binary number 0.101 is indeed 0.625 in decimal.

That’s how you convert a binary decimal to a decimal, but what about a number that contains both decimal and integer parts, like 11.01? Just add the integer and decimal parts separately:


i = 1 n a i x i 1 + j = 1 m a j x j \sum_{i=1}^{n}a_ix^{i-1}+\sum_{j=1}^{m}a_jx^{-j}

In fact, it turns out that when we convert binary to decimal, we don’t have to worry too much about integers and decimals, we just add up the combination: Aixi −1, starting with the decimal point, the number of digits to the left of the decimal point I >=0, and the number to the right of the decimal point I <0. The absolute value of I increases from the decimal point to both sides, so that a floating point number can be directly viewed as a whole.

Similarly, if you convert any other base to decimal, the same is true of the method, and you don’t expand it anymore.

3.2 Converting from decimal to binary

Well, we’ve finally arrived at the last part of the base conversion, the decimal to binary. We still start with the decimal system and use a different decomposition method to decompose a decimal number, such as… 0.123.

The second time we decomposed a decimal integer, we used division, dividing by 10 infinitely until the quotient was 0. For the fractional part, the principle is similar to the whole number part, but the process is slightly different. Let’s divide 0.123 by 0.1 and then separate the whole and decimal parts of the quotient: 0.123÷0.1=1.23=0.23+10.123\ DIV0.1 =1.23=0.23+10.123÷0.1=1.23=0.23+ 10.123 +1

We have two parts: 0.23 and 1, where the 1 is like the remainder of the integer factorization. 0.23 is the quotient, so we continue factorizing 0.23 until the decimal part becomes 0: Present = 2.3 0.1 = 0.3 0.23 = 2.3 = 0.3 + 20.23 + 20.23 \ div0.1 present 0.1 = 2.3 = 0.3 0.3 present 0.1 + 2 = 3 = 0 \ div0.1 = 3 = 0 + 30.3 + 30.3 0.1 = 3 = 0 + 3 members present

Throw away the decimal part of all three, just take the integer part, and put them in order, and put them at 0. After, the result is 0.123. Emmm… There’s a little bit of a problem, because when we did the integer part, at the end of the combination, it looked like the order was reversed, right? The first resolution is the ones place, then the tens place, then the hundreds place, all to the left of the ones place. And here we take the first 1 that we parsed and we put it on the left, and we go to the right. This discrepancy makes it easy for us to make errors in our calculations, and right now, since we’re working in decimal, it’s intuitive and we might be okay with it, but if we’re going to work in binary, this discrepancy will most likely cause us problems.

To solve this problem, we just need to update a concept. That is, for an arbitrary floating-point number, such as 321.123, we throw away all the jumbled concepts of tens, hundreds, left, right, and so on, and simply divide their digits into high and low parts. The decimal point of a number is not a number, we take it as a baseline, it is regarded as the lowest number, starting with the decimal point, the two sides of the number gradually increase, that is, to make the whole appear a V shape.

With that in mind, we look at unpacking and combining: whether integer unpacking or decimal unpacking, the first unpacking digit is placed in its lowest order, the second in its next-lowest order, and so on until the whole combination is complete. That way, the way they combine doesn’t bother us anymore, it’s very natural, from low to high.

Then we’ll see how the decimal part of the decimal system can be converted to binary.

In binary, we should use 2−12^{-1}2−1. However, whether we use 2−12^{-1}2−1 or 0.5, it is not very intuitive when writing and calculating the formula, so a simple adjustment is made here. ÷2−1\div2^{-1}÷2−1 \times2×2. The whole process is the same, we also divide the result into integer and decimal parts, and then take the integer parts, from the lowest to the highest. Let’s take 0.625, the decimal number we used in the previous section, and start counting: 0.625 * 2 = 0.25 + 1.25 = 10.625 \ times2 = 0.25 + 10.625 = 1.25 * 2 = 0.25 1.25 = 0.25 + 1 * 2 = 0.5 = 0.5 \ times2 = 0.5 + 00.25 = 0.5 + 00.25 * 2 = 0.5 + 0.5 = 0 0.5 * 2 = 1 = 0 \ times2 = 1 = 0 + 10.5 + 10.5 * 2 = 0 + 1 = 1

We get the final result: 0.101, which we used in the last section.

3.3 Problems caused by decimals

Now that you know how decimal decimals can be converted to binary, let’s take a look at the problem that was mentioned at the beginning of this article: binary cannot accurately represent decimal fractions.

We used 0.625 to convert to binary 0.101, but not all decimals can be converted to binary 0.101. Here’s a very simple example: 0.1 (decimal). Let’s see what happens if we convert it to binary: 0.1 * 2 = 0.2 + 0.2 = 00.1 \ times2 = 0.2 + 00.1 = 0.2 * 2 = 0.2 0.2 = 0.2 + 0 * 2 = 0.4 + 00.2 = 0.4 \ times2 = 0.4 = 0.4 + 00.2 * 2 = 0.4 + 0.4 = 0 0.4 * 2 = 0.8 + 0.8 = 00.4 \ times2 = 0.8 + 00.4 = 0.8 * 2 = 0.8 0.8 = 0.8 + 0 * 2 = 0.6 + 10.8 = 1.6 \ times2 = = 0.6 + 10.8 * 2 = 1.6 1.6 = 0.6 + 1 Times2 = 0.6×2=1.2=0.2+10.6\times2=1.2=0.2+10.6×2=1.2=0.2 Formula into the loop) 0.2 * 2 = 0.4 + 0.4 = 00.2 \ times2 = 0.4 + 00.2 = 0.4 * 2 = 0.4 + 0.4 = 0 0.4 * 2 = 0.8 + 00.4 = 0.8 \ times2 = 0.8 = 0.8 + 00.4 * 2 = 0.8 + 0.8 = 0 0.8 * 2 = 0.6 + 1.6 = 10.8 \ times2 = 0.6 + 10.8 = 1.6 * 2 = 0.6 1.6 = 0.6 + 1 * 2 = 0.2 + 10.6 = 1.2 \ times2 = = 0.2 + 10.6 * 2 = 1.2 1.2 = 0.2 + 1…

And what we saw is that when you parse this thing, you can’t clear the decimal part, and you have an infinite loop. Predictably, at this rate, the end result for 0.1 binary is 0.0001100110011… It never ends. That’s why binary decimals can’t always accurately represent decimal decimals, and, similarly, numbers like 0.3 and 0.9 can’t really be converted to binary. Because it is not accurate, the computer will give an approximation, and in the process of the approximation, the error gradually exceeds the accuracy of the comparison, resulting in 0.1 + 0.2! = 0.3 BUG.

4. At the end

This article is a bit too many words, you can see here are real heroes. There will probably be another two – or three-part series on binaries (planned), which will cover some of the operations of binaries and their special situations in computers. The words in each of the following chapters should be much less than this one, so that you can look at the less laborious.