Skip to content

2.4 Floating-Point Operations

Java provides two primitive data types for representing floating-point numbers (numbers with decimal points):

  • float: A 32-bit single-precision floating-point number (approximately 6-7 decimal digits of precision).
  • double: A 64-bit double-precision floating-point number (approximately 15 decimal digits of precision).

Declaring Floating-Point Literals

java
float price = 19.99f;    // Note the 'f' suffix for float
double pi = 3.1415926535; // 'd' suffix is optional for double
double largeNumber = 1.23e10; // Scientific notation: 1.23 × 10¹⁰

Basic Arithmetic Operations

Floating-point numbers support the same arithmetic operators as integers:

OperatorOperationExampleResult
+Addition5.5 + 2.37.8
-Subtraction10.0 - 3.76.3
*Multiplication2.5 * 4.010.0
/Division15.0 / 4.03.75
%Modulus10.5 % 3.01.5

Unlike integer division, floating-point division preserves the fractional part:

java
double result = 7.0 / 2.0;  // 3.5, not 3

Special Floating-Point Values

Floating-point arithmetic can produce special values defined by the IEEE 754 standard:

  • Positive Infinity: Result of dividing a positive number by zero.

    java
    double posInf = 5.0 / 0.0;  // Infinity
  • Negative Infinity: Result of dividing a negative number by zero.

    java
    double negInf = -5.0 / 0.0; // -Infinity
  • NaN (Not a Number): Result of undefined operations.

    java
    double nan = 0.0 / 0.0;     // NaN
    double nan2 = Math.sqrt(-1); // NaN

Checking Special Values

java
Double.isInfinite(posInf);  // true
Double.isNaN(nan);          // true

Precision and Rounding Errors

Floating-point numbers use binary representation, which can lead to precision issues with decimal fractions:

java
double result = 0.1 + 0.2;  // Not exactly 0.3!
System.out.println(result);  // 0.30000000000000004

This occurs because numbers like 0.1 cannot be represented exactly in binary floating-point format, similar to how 1/3 cannot be represented exactly in decimal (0.333...).

Type Conversion and Promotion

When mixing different numeric types in operations:

  1. If either operand is double, the result is double.
  2. Otherwise, if either operand is float, the result is float.
  3. Otherwise, if either operand is long, the result is long.
  4. Otherwise, the result is int.

Examples

java
float f = 5.0f;
double d = 10.0;
int i = 3;

double result1 = f + d;  // double
float result2 = f + i;   // float (int promoted to float)
double result3 = d + i;  // double (int promoted to double)

Explicit Casting

java
double precise = 123.456;
float approx = (float) precise;  // Explicit narrowing cast

Comparison and Equality Testing

Due to precision issues, avoid using == for exact floating-point comparisons:

java
// Problematic:
if (0.1 + 0.2 == 0.3) {  // This will be false!
                // Code may not execute as expected
}

// Better approach: use tolerance-based comparison
final double EPSILON = 1e-10;  // Small tolerance value
double sum = 0.1 + 0.2;
if (Math.abs(sum - 0.3) < EPSILON) {
                // Considered equal for practical purposes
}

For comparisons, use:

  • Math.abs(a - b) < tolerance for equality.
  • Standard <, <=, >, >= operators for ordering.

Mathematical Functions

The Math class provides common mathematical operations:

java
double x = 25.0;
double y = 3.0;

double sqrt = Math.sqrt(x);      // 5.0 - square root
double power = Math.pow(x, y);   // 15625.0 - x raised to power y
double abs = Math.abs(-7.5);     // 7.5 - absolute value
double round = Math.round(3.7);  // 4.0 - nearest integer
double ceil = Math.ceil(3.2);    // 4.0 - round up
double floor = Math.floor(3.9);  // 3.0 - round down

// Trigonometric functions (work in radians)
double sin = Math.sin(Math.PI / 2);  // 1.0
double cos = Math.cos(Math.PI);      // -1.0

Best Practices and Common Pitfalls

Best Practices

  1. Prefer double over float for most applications due to better precision.
  2. Avoid == for exact comparisons - use tolerance-based approaches.
  3. Be aware of cumulative errors in repeated calculations.
  4. Use BigDecimal for financial calculations where exact decimal representation is required.
  5. Handle special values (Infinity, NaN) appropriately in your code.
  6. Consider performance implications - floating-point operations are generally slower than integer operations.

Common Mistakes

java
// Mistake 1: Forgetting the 'f' suffix
float wrong = 3.14;       // Error: requires cast or 'f' suffix
float correct = 3.14f;    // Correct

// Mistake 2: Integer division in floating-point context
double result = 5 / 2;    // 2.0, not 2.5 - both operands are integers
double correct = 5.0 / 2; // 2.5 - at least one operand is floating-point

// Mistake 3: Comparing NaN with ==
double nan = 0.0 / 0.0;
if (nan == Double.NaN) {  // Always false!
        // This will never execute
}
if (Double.isNaN(nan)) {  // Correct way to check
        // This will execute
}

Example Code Snippet

java
public class FloatOperations {
    public static void main(String[] args) {
        // Basic operations
        double a = 15.75;
        double b = 4.25;

        System.out.println("a + b = " + (a + b));      // 20.0
        System.out.println("a - b = " + (a - b));      // 11.5
        System.out.println("a * b = " + (a * b));      // 66.9375
        System.out.println("a / b = " + (a / b));      // 3.7058823529411766
        System.out.println("a % b = " + (a % b));      // 3.0

        // Precision example
        double preciseSum = 0.1 + 0.2;
        System.out.println("0.1 + 0.2 = " + preciseSum); // 0.30000000000000004

        // Proper comparison with tolerance
        final double TOLERANCE = 1e-10;
        if (Math.abs(preciseSum - 0.3) < TOLERANCE) {
            System.out.println("0.1 + 0.2 is effectively 0.3");
        }

        // Math class functions
        double number = 16.0;
        System.out.println("Square root: " + Math.sqrt(number));      // 4.0
        System.out.println("Square: " + Math.pow(number, 2));         // 256.0
        System.out.println("Rounded: " + Math.round(3.6));            // 4.0

        // Special values
        double infinity = 5.0 / 0.0;
        double nan = 0.0 / 0.0;
        System.out.println("Infinity: " + infinity);                  // Infinity
        System.out.println("NaN: " + nan);                            // NaN
        System.out.println("Is infinity? " + Double.isInfinite(infinity)); // true
        System.out.println("Is NaN? " + Double.isNaN(nan));           // true
    }
}