slanted W3C logo

Day 04

Today we look at operations with the floating-point types and what happens when types mix in arithmetic expressions.

double

We have already seen the double type used to represent real numbers. The range of values that can be represented by the type is approximately:

Minimum Value Maximum Value
-1.7 × 10308 1.7 × 10308

All of the operators we have seen so far can be used with double types.

Closure

Operations with double can overflow. If overflow occurs, the result is set to a value representing positive infinity (if the value is positive) or negative infinity (if the value is negative).

The value 0.0 / 0.0 is called NaN or not a number. Division by 0.0 with other double values produces either positive or negative infinity.

public class DoubleClosureExamples
{
   public static void main(String[] args)
   {
      // positive overflow
      double x = 1E200;
      System.out.println(x * x);

      // negative overflow
      System.out.println(-x * x);

      // NaN
      double zero = 0.0;
      System.out.println(zero / zero);

      // positive overflow (division by 0.0)
      System.out.println(x / zero);

      // negative infinity (division by 0.0)
      System.out.println(-x / zero);
   }
}

Making Change

Suppose you pay $5.00 for three candy bars costing $1.10 each. How much change should you get back? Write a Java program that solves the problem in three different ways:

  1. for the first way, you should compute the total cost of the candy bars as (3 * 1.10)
  2. for the second way, you should just use 3.30 as the total cost of the candy bars
  3. for the third way, just use the value 1.70.

Use the subtraction operator to calculate the final result, and you should use doubles for the monetary values. Compare all three results using Java's equality operator ==.

Almost $1.70

The following program

public class MakingChange
{
   public static void main(String[] args)
   {
      double change1 = 5.0 - (3 * 1.1);
      double change2 = 5.0 - 3.3;
      double change3 = 1.7;

      System.out.println(change1 == change2);
      System.out.println(change1 == change3);
      System.out.println(change2 == change3);
   }
}

outputs:

false
false
false

Decimal Numbers are Approximations

Almost every decimal number is represented by an approximate value on a computer (because of the way most computers store decimal numbers).

Do not use double to repesent monetary amounts; instead, convert everything to cents and use int or long to perform the calculatioins.

float

The float type is also used to represent real numbers but it has a smaller range and less precision than double. The range of values that can be represented by the type is approximately:

Minimum Value Maximum Value
-3.4 × 1038 3.4 × 1038

A float occupies 4 bytes of memory and has about 7 significant digits. All of the operators we have seen so far can be used with float types. A float literal is a number followed by an F or an f; for example:

Most of the time you would prefer double over float unless lack of memory is an issue.

Mixing Integer and Floating-Point Types

If you mix types in an arithmetic expression the results can be confusing. You need to apply the precedence rules and associativity rules to determine the order in which the operands are evaluated, and then apply the following set of rules:

  1. if one of the operands has type double then the other operand is promoted to type double
  2. otherwise, if one of the operands has type float then the other operand is promoted to type float
  3. otherwise, if one of the operands has type long then the other operand is promoted to type long
  4. otherwise, both operands are promoted to type int

Examples

Assume that for each of the following examples shown in the table below we have the declarations:

double xDouble = 10.0;
float xFloat = 5.0F;
long xLong = 4L;
int xInt = 2;
short xShort = 1;
Expression Evaluation
xFloat + xDouble ⇒ ((double) xFloat) + xDouble
⇒ 15.0
xFloat * xLong ⇒ xFloat * ((float) xLong)
⇒ 20F
xInt - xLong ⇒ ((long) xInt) - xLong
⇒ -2L
xShort + xShort ⇒ ((int) xShort) + ((int) xShort)
⇒ 2
+xShort ⇒ +((int) xShort)
⇒ +1
-xShort ⇒ -((int) xShort)
⇒ -1

Assignment and Mixed Types

In an assignment statement involving the primitive numeric types, the Java compiler will promote the right-hand side value (perform a widening conversion) but it will not demote the value (perform a narrowing conversion).

If you have a variable of type:

  1. double then you can assign to it any value of primitive numeric type
  2. float then you can assign to it any value of primitive numeric type except double
  3. long then you can assign to it any value of primitive integer type
  4. int then you can assign to it any value of primitive integer type except long
  5. short then you can assign to it only values of type short
  6. byte then you can assign to it only values of type byte
  7. char then you can assign to it only values of type char

Casting to Widen a Value

Occassionally, you will want to explicitly perform a widening conversion. For example, suppose you wanted to compute the average of three integers:

public class Average1
{
   public static void main(String[] args)
   {
      int num1 = 10;
      int num2 = 11;
      int num3 = 12;
      int nValues = 3;   // the number of values to average

      double avg = (double) (num1 + num2 + num3) / nValues;

      System.out.println(avg);
   }
}

Java evaluates the average in the example above by

  1. computing the sum (num1 + num2 + num3) as an int (because num1, num2, and num3 are all of type int).
  2. casting the value of the sum to double
  3. now there is a double divided by an int so the value of nValues is converted to double
  4. dividing the two double values to compute the average

Casting to Narrow a Value

Occassionally, you will want to explicitly perform a narrowing conversion. An example is when you compute a quantity using double that is supposed to represent an integer quantity, like the number of hairs on a human head:

// recall that areaCovered is a double
int numberOfHairs = (int) (areaCovered * density);

Casting a double to an int or long discards the decimal part of the number (it does not round); thus, the cast

int someValue = (int) 5.99;

results in someValue having a value of 5. If you want to round the result you need to use a method from java.lang.Math.

Client-View Programming

client
a customer or patron; someone who receives a service

In 1020, the client is you, the programmer of the main method. You are called a client because you will need to shop for components that can provide you with services that can help you solve a programming problem.

We have already used one component named System.out; that component provided us with a service named println that let us send output to a console.

In Java, a component that provides a service is usually what we call an object; occassionally, the component is something else called a utility.

Delegation

to delegate
to entrust to another

As the client, you can choose to entrust information (data) or computation to an object or utility.

What are some advantages of delegating data storage?

What are some advantages of delegating computation?