Free for students · Ad-free · WCAG 2.1 AA Compliant · Accessibility

Casting and Range of Variables

Lesson ~10 min read 8 MCQs

In simple terms: In simple terms, casting is about changing a variable's data type, like turning a decimal into a whole number, and understanding the limits of number storage in Java.

Why this matters

Imagine you and two friends, Maya and Carlos, go out for pizza in downtown Chicago. The total bill comes to $47.00. You decide to split it three ways. You pull out your phone's calculator: 47 divided by 3 is 15.66666... You can't pay a fraction of a cent! You have to convert that decimal into a real-world amount, probably by rounding up to $15.67.

This exact problem happens constantly in programming. Sometimes you have a number with a decimal (double), but you need a whole number (int). How do you make that conversion? Do you just chop off the decimal, or do you round? What happens if a number gets too big for the computer to even hold?

Today, we'll explore how Java handles these situations through casting, and we'll learn how to avoid the strange "overflow" and "round-off" errors that can trip up even experienced programmers.

Concept overview

flowchart TD
    A[Start: Expression with x and y] --> B{Is x or y a double?};
    B -->|No, both are int| C[Integer arithmetic is performed];
    C --> D[Result is an int];
    B -->|Yes| E[The int value is widened to a double];
    E --> F[Double arithmetic is performed];
    F --> G[Result is a double];
    D --> H[End];
    G --> H[End];
This diagram is a flowchart showing how Java handles arithmetic between two numbers. It starts with an expression, checks if either number is a double, and follows one of two paths: one for integer-only math resulting in an int, and one where an int is widened to a double, resulting in a double.

Core explanation

Hello everyone! Let's dive into one of the most practical topics in Unit 1. You'll use these concepts in almost every program you write. We're talking about how to make different number types work together.

From double to int: The Art of Casting

Think of data types like different kinds of containers. A double is like a large pitcher that can hold water with very precise measurements, including fractions of an ounce. An int is like a set of 1-ounce measuring cups. It can only hold whole ounces.

What if you have a value in a double variable, but you need to store it in an int? You can't just pour the pitcher into the measuring cups—you have to make a choice. This is where casting comes in. Casting is you, the programmer, telling Java, "I know these types don't match, but I want you to force this conversion anyway."

The syntax for casting is to put the type you want in parentheses before the value.

double preciseGrade = 92.8;
int wholeGrade = (int) preciseGrade; // wholeGrade is now 92
Casting truncates, it does not round. Use `+ 0.5` for rounding.

How to Actually Round

So what if you do want to round, like in our pizza bill example? The AP exam expects you to know a clever trick.

For any non-negative number x, you can round it to the nearest integer with this formula: (int) (x + 0.5).

Flowchart for rounding a positive number using the `+ 0.5` trick.

Let's see why this works:

  • If x is 92.8, then 92.8 + 0.5 is 93.3. Casting (int)93.3 truncates it to 93. Perfect!
  • If x is 92.3, then 92.3 + 0.5 is 92.8. Casting (int)92.8 truncates it to 92. Also perfect!

For negative numbers, the logic is flipped: you subtract 0.5. (int) (x - 0.5).

From int to double: Automatic Widening

What about going the other way? Putting the contents of a small container into a big one? That's easy! Java does this for you automatically in a process called widening.

If you do math with an int and a double, Java will temporarily "promote" or widen the int to a double before doing the calculation. The result will always be a double.

int dollars = 15;
double taxRate = 0.06;
double totalCost = dollars * taxRate; // This works!
// Java treats `dollars` as 15.0 for this one calculation.

This is super important for division. Look at the difference:

int totalScore = 275;
int numTests = 3;

// Integer division (wrong average)
double avg1 = totalScore / numTests; // 275 / 3 gives 91. The result is 91.0

// Mixed-type division (correct average)
double avg2 = totalScore / 3.0; // 275 / 3.0 gives 91.666... The result is 91.666...

In the first example, Java performs integer division first because both operands are ints. It calculates 91 and only then assigns it to a double. In the second, because 3.0 is a double, Java widens totalScore and performs floating-point division, giving you the precise answer.

When Numbers Get Too Big: Integer Overflow

Your computer doesn't have infinite memory. An int in Java is stored using 4 bytes (32 bits) of memory. This means there's a limit to how big—or small—a number an int can hold.

  • The largest possible int value is 2,147,483,647. You can access this with the constant Integer.MAX_VALUE.
  • The smallest possible int value is -2,147,483,648. You can access this with Integer.MIN_VALUE.

What happens if you have a variable at Integer.MAX_VALUE and you add 1?

int myNumber = Integer.MAX_VALUE; // 2,147,483,647
myNumber = myNumber + 1;
// myNumber is now -2,147,483,648 (Integer.MIN_VALUE)

This is called integer overflow. It doesn't cause an error or crash your program. Instead, the value "wraps around" from the maximum value to the minimum value. Think of a car's odometer hitting 999,999 miles and rolling over to 000,000. It's the same principle. This is a rare but critical bug to be aware of, especially in systems that handle large numbers, like banking software or scientific simulations.

When Decimals Get Weird: Round-off Error

Just like ints have a limited range, doubles have limited precision. They are also stored in a finite amount of memory (8 bytes). They can't store every possible decimal number with perfect accuracy because some fractions (like 1/3 or 1/10) have repeating digits in binary, the computer's native language.

This leads to tiny inaccuracies called round-off errors.

You might expect 0.1 + 0.2 to equal 0.3. But in Java:

System.out.println(0.1 + 0.2);
// Prints: 0.30000000000000004

Whaaat? This tiny error usually doesn't matter for calculating a grade average. But what if you were building a financial system for a bank in Dallas? Those tiny fractions of a cent, when multiplied over millions of transactions, can add up to real money!

This is why for situations that demand perfect precision, like money, programmers often avoid using doubles. A common strategy is to use an int and store the value in cents. For example, to store $47.50, you would store the integer 4750. All your math is done with integers, and you only convert it back to a dollar-and-cent format for display.

Integer division vs. floating-point division.

See it in action

python
Line 1
Output
Click Run to see the output.

        
Try these
    © Shrutam.ai

    Worked examples

    Let's walk through a couple of problems to see these concepts in action.

    Example 1

    Calculating an Average and Rounding

    Problem: Aaliyah has three test scores in her AP US History class: 88, 93, and 97. Write Java code to calculate her average score and store it as a rounded whole number in a variable named finalAverage.

    Solution Walkthrough:

    1. 1
      Store the scores
      First, let's put the scores into int variables.
      int score1 = 88;
      int score2 = 93;
      int score3 = 97;
    2. 2
      Calculate the sum
      This is straightforward.
      int sum = score1 + score2 + score3; // 88 + 93 + 97 = 278
    3. 3
      Calculate the precise average
      Here's the critical step. If we just divide sum / 3, we'll get integer division (278 / 3 = 92). The .666... part will be lost before we can even think about rounding. To prevent this, we must make sure one of the numbers in the division is a double. Dividing by 3.0 is the easiest way.
      double preciseAverage = sum / 3.0; // 278 / 3.0 = 92.666...
    4. 4

      Round the result and cast to an int. Now we have 92.666... and we need to round it to the nearest whole number, which should be 93. We use the (int)(x + 0.5) trick.

      int finalAverage = (int) (preciseAverage + 0.5);
      // preciseAverage + 0.5  -->  92.666... + 0.5  -->  93.166...
      // (int) 93.166...       -->  93

    Final Code:

    int score1 = 88;
    int score2 = 93;
    int score3 = 97;
    int sum = score1 + score2 + score3;
    double preciseAverage = sum / 3.0;
    int finalAverage = (int) (preciseAverage + 0.5); // finalAverage is 93

    Example 2

    Spotting an Integer Overflow

    Problem: A popular mobile game tracks a player's score as an int. The current high score, held by a player named Jordan, is 2,147,483,640. Jordan plays one more game and scores 10 more points. What will the game register as Jordan's new high score?

    Solution Walkthrough:

    1. 1
      Identify the starting values
      The current score is an int, and it's very close to the maximum possible value for an int.
      • currentScore = 2147483640
      • pointsToAdd = 10
      • Integer.MAX_VALUE is 2,147,483,647.
    2. 2
      Analyze the addition
      The new score will be currentScore + pointsToAdd. Let's think about what happens as we add the 10 points one by one.
      • ... + 1 -> ...641
      • ... + 2 -> ...642
      • ...
      • ... + 7 -> 2,147,483,647 (This is Integer.MAX_VALUE)
    3. 3
      Predict the overflow
      We've now added 7 of the 10 points. What happens when we add the 8th point?
      • 2,147,483,647 + 1 will cause an overflow. The value wraps around to Integer.MIN_VALUE, which is -2,147,483,648.
    4. 4
      Calculate the final value
      We've used 8 points. We still have 2 more points to add to the new, negative score.
      • -2,147,483,648 + 1 -> -2,147,483,647
      • -2,147,483,647 + 1 -> -2,147,483,646

    Final Answer: Jordan's new score will be -2,147,483,646. Instead of getting a new high score, the overflow bug makes it look like Jordan has an impossibly low, negative score.

    Tracing the calculation of an average with correct rounding.
    Avoiding integer division for precise averages.

    Try it yourself

    Time to put your knowledge to the test. Try to solve these on your own before looking up the answer.

    Problem 1: Sales Tax You're buying a new video game in Seattle for $59.99. The sales tax is 10.25%. Write a single line of Java code that calculates the total cost (price + tax) and stores it as a double in a variable named totalCost. Then, write a second line of code to determine the number of whole dollars you need to pay, storing it in an int variable named dollarsToPay. (Hint: You can't pay in fractions of a dollar, so if the total is $66.13, you need 67 dollars to cover it. How can you model this?)

    Problem 2: Predicting an Overflow A variable score is currently set to Integer.MIN_VALUE. What is the value of score after the line score = score - 1; is executed? Think about the odometer analogy, but in reverse.

    Visualizing integer overflow: an odometer analogy.