Mixing Data Types

C and Fortran allow you to mix numeric data types in expressions. This should be avoided as much as possible, however, for two reasons:

Implicit Data Conversions

Promotions occur when two different data types are used as operands to a mathematical operator. In all cases, the value of the lower ranking type is converted to the higher ranking type.

The rules of promotion are as follows:

  1. Complex types have the highest rank. Any other numeric type mixed with a complex value will be promoted to complex.
  2. Floating point values have the next highest rank. Integers mixed with floating point values will be promoted to the floating point type.
  3. Integers have the lowest rank and are always promoted to other types they are mixed with.
  4. Within each general category of types (complex, floating point, and integer), a larger type ranks higher than a smaller one. E.g., a char will be promoted when mixed with any other integer, a short will be promoted when mixed with an int, and an int will be promoted when mixed with a long. A float is promoted when mixed with a double.
  5. It is almost always a bad idea to mix signed and unsigned integers.
  6. Integer types smaller than int (char and short) are promoted even when not being mixed with higher types, just to prevent overflow. Promotion occurs when performing arithmetic operations on the values and when passing them to functions, such as printf(). This means that adding two char or short values takes longer than adding two int values.

    The program below demonstrates. The maximum value we can store in an unsigned short is 65,535. 32,768 + 32,768 is 65536. When we add a + b, the result is 65,536, which requires 17 bits to represent. The values from a and b are promoted to int before the addition occurs, so the expression a + b has type int and the expected value of 65,536. However, when this value is assigned to c, the leftmost bit is lost and c ends up getting 0. The expression a + b / 2 also has type int, but dividing by 2 reduces its value to something that fits in a short, so d gets 32,768, not 0.

    #include <stdio.h>
    #include <sysexits.h>
    
    int     main(int argc,char *argv[])
    
    {
        unsigned short  a, b, c, d;
        
        a = 32768;
        b = 32768;
        c = a + b;          // a + b is 65,536, beyond the range of c
        d = (a + b) / 2;    // a + b / 2 is 32,768, within the range of d
        
        // Output is 32768 32768 0 32768
        printf("%d %d %d %d\n", a, b, c, d);
        return EX_OK;
    }
                    

Demotions occur only when assigning an expression to a variable of a lower ranking type:

integer :: area
real(8) :: height, width

height = 4.5
width = 1.3

! Oops, lost the fractional part!  area gets 5, rather than 5.83
area = height * width
            

Note that when assigning any type of real value to an integer variable, the value is truncated, not rounded.

The type of a variable or constant is never changed. The promoted value is stored in a temporary memory location, and discarded when the program finishes evaluating the expression.

The examples below show all the steps necessary to evaluate a mixed expression, including calculations and implicit conversions. Note how implicit conversions can account for a significant fraction of the total operations.

Note also that some conversions, such as integer to floating point, can be rather expensive.

int     a, b, d;
double  x;

a = 4;
b = 6;
x = 3.0;
d = b / a + x * 5.0 - 2.5;
            
Expression                  Steps completed             Notes
d = b / a + x * 5.0 - 2.5
d = 1 + x * 5.0 - 2.5       Integer division b / a      1, not 1.5!
d = 1 + 15.0 - 2.5          Double multiplication
d = (double)1 + 15.0 - 2.5  Promote 1 to double         No work completed
d = 16.0 - 2.5              Double addition
d = 13.5                    Double subtraction
d = (int)13.5               Demote 13.5d0 to integer    No work completed
d = 13                      Assign result to d
            
integer :: a, b, d
real(8) :: x

a = 4
b = 6
x = 3.0d0
d = b / a + x * 5.0 - 2.5
            
Expression                  Steps completed             Notes
d = b / a + x * 5.0 - 2.5
d = 1 + x * 5.0 - 2.5       Integer division            1, not 1.5!
d = 1 + x * dble(5.0) - 2.5 Promote 5.0 to real(8)      No work completed
d = 1 + 15.0d0 - 2.5        Double multiplication
d = dble(1) + 15.0d0 - 2.5  Promote 1 to real(8)        No work completed
d = 16.0d0 - 2.5            Double addition
d = 16.0d0 - dble(2.5)      Promote 2.5 to real(8)      No work completed
d = 13.5d0                  Double subtraction
d = int(13.5d0)             Demote 13.5d0 to integer    No work completed
d = 13                      Assign result to d 
            

Even assuming that the CPU running this program can convert from one data type to another with a single instruction, this code would run significantly faster if all the variables and constants were the same data type to begin with. If the CPU cannot convert data types with a single instruction, this statement will be many times slower than necessary.

The compiler's optimizer may be able to eliminate some promotions at run-time by performing them at compile-time. Nevertheless, mixing data types will usually slow down your code to some extent.

Explicit Data Conversions

In C, we can convert from one data type to another by simply prefixing the expression with the desired data type in parenthesis. This is known as casting the expression.

int a = 1, b = 2;
double x;

// Convert value in a to double before division. This will cause an
// implicit promotion of the value of b when division occurs and
// produce a result of 0.5 instead of 0.
x = (double)a / b;

// We can explicitly convert both a and b, but the result is exactly the same
x = (double)a / (double)b
            

Explicit data conversions can be performed in Fortran 90 using intrinsic functions. For example, to force a real division of two integer variables, we could do the following:

integer :: a = 1, b = 2
real(8) :: x

// Convert value in a to double before division. This will cause an
// implicit promotion of the value of b when division occurs and
// produce a result of 0.5 instead of 0.
x = dble(a) / b 
            

Table 17.10. Explicit Conversion Functions

FunctionDescriptionReturns
int(A)Truncated integerinteger
int2(A)Truncated 16-bit integerinteger(2)
int8(A)Truncated 64-bit integerinteger(8)
nint(A)Nearest integerinteger
real(A)Nearest realreal
dble(A)Nearest real(8)real(8) [ double precision ]
cmplx(R [,I])Nearest complexcomplex
dcmplx(R [,I])Nearest double complexdouble complex [ complex(8) ]

Practice

Note

Be sure to thoroughly review the instructions in Section 2, “Practice Problem Instructions” before doing the practice problems below.
  1. What are two reasons to avoid mixing data types and mathematical expressions?

  2. When do promotions occur in C and in Fortran?

  3. When do demotions occur?

  4. How do we explicitly convert a value to a different data type in C? In Fortran?

  5. What is the output of the following code segment? ( First try to determine it by reading the code, then type it in and run it to verify. )

        int     a, b, c;
        double  x, y;
        
        a = 1;
        b = 2;
        c = 3;
        x = 4.0;
        y = 5.0;
        
        printf("%d\n", a / b);
        printf("%d\n", 3 / 4);
        printf("%d\n", c / 2);
        printf("%f\n", x / y);
        printf("%f\n", c / x);
        printf("%f\n", sqrt(x));
            
        integer :: a, b, c
        real(8) :: x, y
        
        a = 1
        b = 2
        c = 3
        x = 4.0d0
        y = 5.0d0
        
        print *, a / b
        print *, 3 / 4
        print *, c / 2
        print *, x / y
        print *, c / x
        print *, x ** (1/2)