Cautions With for Loops

The Program

/***************************************** Program: beers.c Author: An unknown UMBC Student Date: Every Semester Section: Can never remember Email: unknown@umbc.edu How many beers are left after 5 rounds? *****************************************/ #include <stdio.h> int main() { /* Declare variable */ float beers ; /* You'd think this loop will count down from ** 1.0 to 0.0 by the step -0.2, singing each verse ** as it goes, but does it ? */ for (beers = 1.0; beers != 0.0; beers -= 0.2) { printf("%f %s\n%f %s\n", beers, "bottles of beer on the wall", beers, "bottles of beer"); printf("Take a fifth down, pass it around\n"); printf("%e bottles of beer on the wall\n\n", beers - 0.2 ); } return 0; }

The Sample Run

1.000000 bottles of beer on the wall 1.000000 bottles of beer Take a fifth down, pass it around 8.000000e-01 bottles of beer on the wall 0.800000 bottles of beer on the wall 0.800000 bottles of beer Take a fifth down, pass it around 6.000000e-01 bottles of beer on the wall 0.600000 bottles of beer on the wall 0.600000 bottles of beer Take a fifth down, pass it around 4.000000e-01 bottles of beer on the wall 0.400000 bottles of beer on the wall 0.400000 bottles of beer Take a fifth down, pass it around 2.000000e-01 bottles of beer on the wall 0.200000 bottles of beer on the wall 0.200000 bottles of beer Take a fifth down, pass it around 3.278255e-08 bottles of beer on the wall 0.000000 bottles of beer on the wall 0.000000 bottles of beer Take a fifth down, pass it around -2.000000e-01 bottles of beer on the wall -0.200000 bottles of beer on the wall -0.200000 bottles of beer Take a fifth down, pass it around -4.000000e-01 bottles of beer on the wall -0.400000 bottles of beer on the wall -0.400000 bottles of beer Take a fifth down, pass it around -6.000000e-01 bottles of beer on the wall -0.600000 bottles of beer on the wall -0.600000 bottles of beer Take a fifth down, pass it around -8.000000e-01 bottles of beer on the wall -0.800000 bottles of beer on the wall -0.800000 bottles of beer Take a fifth down, pass it around -1.000000e+00 bottles of beer on the wall -1.000000 bottles of beer on the wall -1.000000 bottles of beer Take a fifth down, pass it around -1.200000e+00 bottles of beer on the wall

The Lesson


Fractions in base 2

In base ten (decimal), we use 0.1 to represent 1/10, 0.01 to represent 1/100, 0.001 to represent 1/1000, and so on. In base two (binary), we use 0.1 to represent 1/2, 0.01 to represent 1/4, and 0.001 to represent 1/8, etc.

We can determine the binary representation of a fraction using the following strategy. Suppose the number is stored in the (float or double) variable fraction. Then we can print out each digit of the number's binary representation as follows:

   while (fraction > 0) 
   {
      fraction = fraction * 2 ;
      if (fraction >= 1.0)
      {
         digit = 1 ;
         fraction = fraction - 1.0 ;
      }
      else
      {
         digit = 0 ;
      }
      printf("%d\n", digit) ;
   }

Using this strategy, we can figure out that the binary representation of 5/8 = 0.625 (base 10) is 0.101 (base 2). The value of the variables fraction and digit during each iteration of the loop are (in base 10):

   iteration   fraction   digit
      1         0.625
                1.25        1
                0.25

      2         0.25
                0.5         0

      3         0.5
                1.0         1
                0.0

We can check our answer by noting that 1/2 + 1/8 = 5/8, which is what 0.101 (base 2) means.

If we try the same for 1/5, we will notice that the loop never ends. So, 1/5 cannot be represented by a finite number of digits in base 2. This is analogous to the fact that 1/3 is cannot be represented using a finite number of digits in base 10.

   iteration   fraction   digit
      1         0.2
                0.4        0

      2         0.4
                0.8        0

      3         0.8
                1.6        1
                0.6
      
      4         0.6
                1.2        1
                0.2 
         
      5         0.2
                0.4        0
       
      6         0.4 
                0.8        0
      
      7         0.8
                1.6        1
                0.6
   
      8         0.6
                1.2        1

      9         0.2
                0.4        0

     10         0.4
                0.8        0   
      
     11         0.8
                1.6        1
                0.6
      
     12         0.6
                1.2        1
     ...
So, 1/5 is 0.0011001100110011... (base 2) repeating.