COSC 1320 C/C++ Programming

Types
  1. The fundamental types in C are char (character), int (integer) and float. Some compilers include the bool data type.
    1. char
      char is the character type. It usually hold 8 bits which stores an encoded character. The standard encoding scheme is ASCII. However, other encoding schemes such as EBCDIC can be used.

      In C you can manipulate variables defined as character using the same operations that apply to integers.
      #include <iostream>
       
      using namespsce std;
      void main()
      {
        char letter = 'a';
       
        cout << letter;
        letter=letter+1;
        cout << letter;
      }
       
      a
      b
      
    2. bool The bool type takes one byte and stores a value of true (1) or false(0).

    3. int
      int is the integer data type. Integers are represented in binary format.
      1. Binary numbers may be stored in either 1's or 2's complement form. Most machines use 2' complement. To form 1's complement just invert the bits. For two complement invert the bits and add one. An interesting property of one's complement is that there are two ways to represent zero.

        In binary arithmetic subtraction is done by complementing a number and then adding it. To add binary numbers use the following rules.
         0 + 0 = 0
         0 + 1 = 1
         1 + 0 = 1
         1 + 1 = 10
         
        for ease 1 + 1 + 1 = 11
         
        to add 7 + 4
         
             7 =    111
             4 =    100
                   ----
             11 =  1011
         
        to subtract 7 - 6
         
            7 = 111
            6 = 110 first form the two's complement 001 + 1 = 010
         
        then add
            7 = 111
                010
              -----
               1001
         
        ignore the final carry and the answer is 001 = 1.
        

      2. The range of integer variable is determined by the size of the integer. For an integer with n bits the range on a two's complement machine is:

        - 2 n-1 .. 2 n-1 -1

        On a one's complement machine the lower bound becomes

        - 2n-1 -1

        Since most machines use two's complement you can usually expect:
          Bits                 Low                  High
          16               -32,768                32,767
          32        -2,147,483,648         2,147,483,647
        
      3. C++ supports the concept of unsigned integers like
        unsigned int k;
        Then the range becomes:

        0 ... 2n -1

      4. The C/C++ compilers accept the integer modifiers short and long for integers, but the implementation is left to the hardware. You are guaranteed that a short will be no bigger than an int and a long will be no smaller than an int.

    4. float
      real numbers are stored as floating point approximations of the number. Floating point numbers are divided into exponent and mantissa, with one bit reserved for the sign of the number. In most hardware the mantissa is normalized between 0 and 1. The number of bits devoted to the mantissa determines the precision of the number, or how many digits may be represented. The number of bits in the exponent determines the range (magnitude) of the number. C has a double ( meaning double precision) type that extends the mantissa. Different manufactures use various schemes to divide up the exponent and mantissa. As the following table represents various 64 bit schemes

      VendorExponent bitsLowHighMantissa bitsDecimal Digits
      IEEE11-3083085216
      Cyber11-2933234815
      IBM 30817-79755616
      VAX D7-39385617
      VAX G11-3093075216
      Cray15-246624654814


      In representing a floating point number if the exponent exceeds the the maximum we say an overflow has occurred. If the exponent becomes smaller than the minimum, we say an underflow has occurred.

      1. Since floating number numbers are approximations to the actual number there exist a problem with roundoff errors as demonstrated here:
        #include <iostream>
         
        using namespace std;
         
        int main()
        {
         float value,sum;
         double dsum;
         int count;
         
         sum=dsum=0.0;
         value=1.0e-3;
         cout << "Adding 1/1,000 1,000 times " << "\t";
         for(count=0;count<(int)1.0e3;count++) {
            sum+=value;
            dsum+=value;
         }
         cout << "float=" << sum << "\t" << "double=" << dsum <<endl;
         
         sum=dsum=0.0;
         value=1.0e-4;
         cout << "Adding 1/10,000 10,000 times " << "\t";
         for(count=0;count<(int)1.0e4;count++) {
            sum+=value;
            dsum+=value;
         }
         cout << "float=" << sum << "\t" << "double=" << dsum <<endl;
         
         
         sum=dsum=0.0;
         value=1.0e-5;
         cout << "Adding 1/100,000 100,000 times " << "\t";
         for(count=0;count<(int)1.0e5;count++) {
            sum+=value;
            dsum+=value;
         }
         cout << "float=" << sum << "\t" << "double=" << dsum <<endl;
         
         
         system("pause");
         return 0;
        }
        

        When this program is run the results are:
        Adding 1/1,000 1,000 times      float=0.999991  double=1
        Adding 1/10,000 10,000 times    float=1.00005   double=1
        Adding 1/100,000 100,000 times  float=1.00099   double=1
        Press any key to continue . . .
        

      2. When doing floating point arithmetic we are concerned with "what is the smallest value that will make a difference in logical operations?". This is called the machine epsilon. It can be computed:
        #include <iostream>
         
        using namespace std;
        int main()
        {
         float epsilon;
         int count=0;
         
        
         epsilon=1.0;
         
         cout << "Computing machine epsilon " << endl;
         while(1.0+epsilon > 1.0) {
              count++;
          epsilon/=2;
         }
         epsilon*=2;
         cout << "It took " << count << " iterations to compute epsilon = " << epsilon << endl;
         system("pause");
         return 0;
        }
         
        

        When this was compiled and run the result was:
        Computing machine epsilon
        It took 64 iterations to compute epsilon = 1.0842e-019
        Press any key to continue . . .
        


        Since the floating point values are approximations, this leads us to an important rule of thumb.
        NEVER USE EQUALITY TESTS ON FLOATS

  2. Mixed type expressions.
    If the operands are the same type then the result is of that type. If operands are of different types, the "narrow" types are converted to the "widest" type in the expression. This automatic promotion follows the general progression:
    char->short->int->long->float->double
     int k=5;
     float x,y=20.0;
     
     x=y/k;
    
    1. The assignment operator uses the type of the left hand side. This may cause warnings when demotion occurs.
    2. To change the type explicitly use the static_cast notation.
        float x;
        int a=7, b=3;
       
        x=a/b;
      
      What is the result?
        float x;
        int a=7, b=3;
       
        x=a/b;
      
      Now what is the result?

  3. Size of Variables
    The size of different types can be discovered with the sizeof operator. It returns the size of the variable ( or structure) in bytes (8 bits). The following program will print out the sizes of the different types.
    #include <iostream.h>
    void main()
    {
     cout << "char   " << sizeof(char)   << endl;
     cout << "short  " << sizeof(short)  << endl;
     cout << "int    " << sizeof(int)    << endl;
     cout << "long   " << sizeof(long)   << endl;
     cout << "float  " << sizeof(float)  << endl;
     cout << "double " << sizeof(double) << endl;
    }
    
    I got the following results from running on different architectures:
    Size of Variables
    TypeVaxSunConvexCrayApolloMS VC++
    char 111111
    short 222822
    int 444844
    long 444844
    float 444844
    double888888

    Running on the dev C++ compiler I get:
    char   1
    bool   1
    short  2
    int    4
    long   4
    float  4
    double 8
    Press any key to continue . . .
    

  4. Declaring Variables
    In general variables may be declared inside of a block of code. A block is denoted by { }. Variables inside of a block are local to that block.
    int main()
    {
      int a,b;
      float c;
      char d;
    }
    
    1. Variables may be initialized when declared with the = operator like:
      int main() 
      {
        int a=1;
        float b=1.2e3;
        char c='a';
      }
      
      Local variables are initialized every time the block of code is executed.
      #include <iostream>
      using namespace std;
       
      void f();  // function prototype
       
      int main()
      {
         f();  // call function f
         f();  // call function f
         system("pause");
         return 0;
       
      }
      void f()  // function f
      {
        int localX=1;     // declare and set local varaible
       
        cout << "In Function f " << endl;
        cout << "localX is " << localX << endl;
        localX=2;
        return;
      }
       
      

      In Function f
      localX is 1
      In Function f
      localX is 1
      Press any key to continue . . .
      

  5. Conditions
    #include <limits>
    #include <float.h>
    #include <iostream>
     
    using namespace std;
    int main()
    {
      int max=INT_MAX;
      cout << "The maximum value for an integer is : " << max << endl;
      cout << "Add +1 to go over the max - overflow" << endl;
      max++;
      cout << "Now the value is : " << max << endl;
      cout << endl;
     
      float maxf= FLT_MAX;
      cout << "The Maximum Float Value is : " <<  maxf <<endl;
      cout << "Times 1 million to force overflow" << endl;
      maxf*=1.0e6;
      cout << "After overflow : " << maxf <<endl;
      cout << endl;
      
      float minf=FLT_MIN;
      cout << "The Minimum Float Value is  " << minf << endl;
      cout << "Divide by 1 trillion to force underflow " << endl;
      minf/=1.0e12;
      cout << "After underflow : " << minf << endl;
     
      system("pause");
      return 0;
    }
     
    

    The maximum value for an integer is : 2147483647
    Add +1 to go over the max - overflow
    Now the value is : -2147483648
     
    The Maximum Float Value is : 3.40282e+038
    Times 1 million to force overflow
    After overflow : 1.#INF
     
    The Minimum Float Value is  1.17549e-038
    Divide by 1 trillion to force underflow
    After underflow : 0
    Press any key to continue . . .