Kevin's Guides

# BigDecimals, Mutability, and Basic Memory Concepts

In this chapter, we will study BigDecimals and learn about how the JVM handles them in system memory. The BigDecimal class is used to perform calculations when precision and rounding are of great importance. This makes them useful if you need to perform exact calculations involving money or other sensitive data. In Chapter 3, we discussed the use of doubles and floats to represent values containing decimals. To illustrate the problem with precision when using floats, let’s examine a sample problem.

Imagine you are creating a banking application. The application works with large monetary transactions. A wealthy client wants to transfer thirty million dollars out of his bank account. The bank charges a low transaction fee of 0.001542%. Let’s see what happens when we calculate the transaction fee using floats.

Example 5.1a: Money Transfer
float transactionFeeRate = 0.00001542f;
float largeMoneyTransfer = 30000000.00f;
float transactionFee = largeMoneyTransfer * transactionFeeRate;

System.out.printf("The transaction fee for this transfer is: %f", transactionFee);


If you do the math, you find that $$30,000,000\times0.00001542 = 462.6$$. However, this does not match what Java will output:

The transaction fee for this transfer is: 462.600006

Although very close, you see that there is an extra fraction of a penny at the end of this calculation which does not belong there. This is because of a rounding error resulting from floats not being precise enough to handle this type of calculation. While it may not be a big issue for this single transaction, imagine the bank is handling tens of thousands of transactions each day, and each one is off by a fraction of a penny. Over time, the accounts could be off by a substantial amount. This is where BigDecimals come in to save the day.

BigDecimals allow us to store very large or small numbers and perform precise calculations following rounding rules we define. The downside to performing calculations with BigDecimals instead of doubles or floats is that they require more processing power, so they put more strain on the CPU. Therefore, if you don’t need to use BigDecimals in non-precise applications, you shouldn’t use them.

#### Declare & Use BigDecimals

Before we can use BigDecimals in applications, we must import them from the Java API. This is just like when we imported Scanners in the previous chapters. The BigDecimal class can be imported from the math package using the following statement at the top of a class file.

import java.math.BigDecimal;

Recall that before objects can be used, they must be declared and instantiated. Just like instance variables for new Scanners must be declared before they can be used, new BigDecimals must be declared. The format for declaring and instantiating a new BigDecimal is as follows:

BigDecimal myBigDecimal = new BigDecimal("3.14");

The format for creating Objects in Java is the same regardless of the object type. In this example, a BigDecimal was created the same way Scanners were created, except instead of using the input stream as our argument, this time the String containing the number "3.14" is the argument. The code is creating a new BigDecimal object with the identifier "myBigDecimal" and then the BigDecimal Class will convert that String into a BigDecimal.

Why was a String in the argument instead of just typing 3.14, without the quotation marks? A String ensures the value is accurate. Although you can create BigDecimals with double values like this: new BigDecimal(3.14), since doubles are not 100% precise, it's better to use a String like ("3.14"). This ensures the value will not be distorted like the float in the first example.

We can print out the values of BigDecimals the same way we printed out other types of variables.

Example 5.1b: BigDecimals
import java.math.BigDecimal;

public class Main {
public static void main(String[] args) {
BigDecimal myBigDecimal = new BigDecimal("3.14");
System.out.println("The value of myBigDecimal is: "+myBigDecimal);
}
}

The output of the above code is:

The value of myBigDecimal is: 3.14

## 5.2: Basic BigDecimal Operations

Now let's look at a few examples where we perform standard operations using BigDecimals. Instead of using the arithmetic operators like we did with primitive data types, we must use the methods provided to us from the BigDecimal class. Let's take a look at the addition method .add();. The following example uses the add method to add two BigDecimals together.

Example 5.2a: BigDecimal Sum
BigDecimal aDecimal = new BigDecimal("22.5");
BigDecimal bDecimal = new BigDecimal("55.0");

System.out.println(sum);
77.5

Note that I didn't need the new keyword for the sum variable. This is because the .add method automatically returns (gives us) a new BigDecimal containing the sum.

The methods to add(), subtract(), multiply(), and divide() all work pretty much the same way. The following example shows the usage of these four methods.

5.2b: BigDecimal Operations
BigDecimal x = new BigDecimal("5");
BigDecimal y = new BigDecimal("2");

BigDecimal difference = x.subtract(y);
BigDecimal product = x.multiply(y);
BigDecimal quotient  = x.divide(y);

System.out.println("The sum is " + sum);
System.out.println("The difference is " + difference);
System.out.println("The product is " + product);
System.out.println("The quotient is " + quotient);
The sum is 7
The difference is 3
The product is 10
The quotient is 2.5

##### 5.2 - Try It Yourself Exercise

Directions: Recreate the first example, Example 5.1a, but instead of using Floats use BigDecimals. It should calculate $$30,000,000\times0.00001542 = 462.6$$ exactly.

Solution Exercise 5.2:
import java.math.BigDecimal;

public class Main {
public static void main(String[] args) {
//Create BigDecimals
BigDecimal transactionFeeRate = new BigDecimal("0.00001542");
BigDecimal largeMoneyTransfer = new BigDecimal("30000000.00");
//Multiply them
BigDecimal transactionFee = transactionFeeRate.multiply(largeMoneyTransfer);
//Print results
System.out.print("The transaction fee for this transfer is: " + transactionFee);
}
}
The transaction fee for this transfer is: 462.6000000000

## 5.3: Memory, Reference Types, and Mutability

We will now examine some fundamental concepts behind how the JVM manages memory for our programs. Having a solid foundation on how this works will make it easier for you to understand the nature of BigDecimals and the behaviors of other objects in Java. We briefly touched on some of this in the last chapter when we learned about how Strings are compared.

The amount of memory the JVM reserves for programs depends on what the JVM expects the program to do. Some programs may require more memory than others, some may require a fixed amount of memory, and some may require dynamically allocated (changing) amounts of memory depending on what code's currently being executed. We don't have to worry about this too much for now, as the JVM takes care of memory management automatically. In the interest of keeping this section relatively simple, we will only be focusing on the basics of how the JVM handles memory in two key areas known as the stack and the heap.

### The Stack

The stack is a linear data structure used to reserve memory for the local variables of our methods in active use. If we never use a variable in our code, the JVM may never even reserve space for it as it's not needed. Local variables are variables used within the scope of a single method. So far in this series we have only been creating programs within the main method, therefore all our variables have been local variables. Starting in the next chapter we will begin creating additional methods utilizing different types of variables. Local variables can only be used within the method that created them.

This area of memory is called a stack because we can visually think of it just like a stack. The stack is composed of stack frames stacked on top of each other. The first stack frame at the bottom would be the main method, as it's the entry point to our program. If the main method calls other methods, they are given their own frames on top of the main method. Every time we call a method, a frame is added to the stack.

Although we haven't created other methods ourselves so far in this series, we have utilized other object's methods perform certain functions, such as when we used Scanners to read user input. Whenever we used the Scanner's methods to retrieve user input such as .nextLine() or .nextInt(), the JVM was creating separate stack frames for those methods.

For example, take a look at this program program which reads a user's input with a Scanner, and then checks if they entered the String "hello world"

5.3a: Stack Execution Example
import java.util.Scanner;

public class Main {
public static void main(String[] args) {
Scanner userInput = new Scanner(System.in);
System.out.println("Enter the message: hello world");
String userMessage = userInput.nextLine();
userInput.close();

if(userMessage.equals("hello world")){
System.out.println("You know how to type! Good job.");
}
else{
System.out.println("Fail.");
}
}
}
Enter the message: hello world
hello world
You know how to type! Good job.

In the above example, seven stack frames were created and used. First, the program started executing the main method in the stack frame at the bottom. Once it got to line 5 where the Scanner was created, we called the Scanner's constructor method to create the scanner. We will discuss constructors more in the next chapter. When we created an instance of Scanner, a stack frame was added for the constructor method.

After the Scanner was constructed, the JVM is done with the second frame. So it is removed from the stack. The frame and its contents disappear at this point, and the memory is free for other stack frames to use.

It then encounters the .println() method and creates a third frame for that. Once that's done it returns to main and calls the nextLine() method with a fourth frame being generated. Then the fifth, sixth, and seventh frames are created in their respective order for the close(), equals(), and println() methods.

We glanced over local variables in the previous example to show the basics of how the stack works. Now let's look at a program that uses local variables of type int to perform a simple calculation. Note that ints can exist in the stack and in the heap depending on how they are used. For this example we will focus on ints that are only stored in the stack.

5.3b: Local ints to printf
public class Main {
public static void main(String[] args) {

int x = 5;
int y = x;
int z = 10;
x = y + x;
System.out.printf("x is %d y is %d and z is %d", x, y, z);

}
}

Primitive data types like ints can be stored directly in the stack. When we change the values of these data types, the values are directly edited at a specific location in memory which remains the same. When we copy a variable, like int y = x; the JVM is creating a second copy of the variable and allocating space for it at a different location in memory. This way, when we modify the value of x later on, the value of y remains 5. When we are accessing, modifying, or comparing values directly, it is said that we are accessing the variable by value. Primitive data types are always accessed by value.

### The Heap

The heap is a dynamically allocated area of memory the JVM uses to storing object information while the program is in use. Objects in the heap are referenced by variables in the stack called object reference variables. In some situations, primitive data types may also be stored in the heap, such as when they are part of another Class. Strings, Scanners, and BigDecimals are all examples of objects we've discussed so far which would get stored in the heap.

In the following example, three BigDecimals are declared, x, y, and z.

5.3c: BigDecimal Equality by Reference
import java.math.BigDecimal;

public class Main {
public static void main(String[] args) {
BigDecimal x = new BigDecimal("5");
BigDecimal y = x;
BigDecimal z = new BigDecimal("5");
System.out.println(x==y);
System.out.println(x==z);
System.out.println(y==z);
}
}
true
false
false

On line 4 of the above example, the object reference variable value for y is being set to the same object reference value of x. The variables x and y are now pointing to the same BigDecimal in the heap. This is why the equality relational operator returns true for the first println on line 8, but false on lines 9 and 10. Even though they all have the same value, x and y are the only variables pointing to the same object. The variable y is not equal to z, and z is not equal to x, because they're pointing to different BigDecimals in the heap.

Although it appears almost as if we're passing objects by reference in the case of x and y, information itself is always passed by value in Java. In this case, the value of the location we're referencing is passed by value and copied over from x to y, but we are not passing the object itself from x to y by reference. In other words, x and y are two separate entities who just so happen to be referencing the same object at this time. To clarify exactly what is meant by this, consider the following example:

Example 5.3d
import java.math.BigDecimal;

public class Main {
public static void main(String[] args) {
BigDecimal x = new BigDecimal("55");
BigDecimal y = x;
x = new BigDecimal("100");
System.out.println(x);
System.out.println(y);
}
}

The above code outputs:

100
55

If Java passed objects by reference it would have output:

100
100

In the above example, if y was set to x by reference, y would be x. On line 7 when we set x to point to a new BigDecimal with value 100, y remained pointed at the BigDecimal 55. If objects in Java could be truly passed by reference, when we set x equal to the new BigDecimal("100"), both x and y would have printed out 100. The 55 would be gone. So remember, if you ever hear that Objects in Java are passed by reference, it's not technically correct. The object variable references are passed by value. The objects themselves are NOT passed by reference.

#### Mutability

Finally, BigDecimals are immutable. Many objects in Java are immutable. An object is immutable if its properties cannot be changed after it is created. This helps to protect the data the BigDecimal contains. In other words, once we make it, we cannot change its values. We can only replace the existing reference with a reference to a new object.

The following example demonstrates creating a BigDecimal and then "changing" its value by overriding it with another BigDecimal. An example with an int is provided for comparison.

Example 5.3e: Replacing References
import java.math.BigDecimal;

public class Main {
public static void main(String[] args) {

//Create BigDecimal and give it a value of 10
BigDecimal aBigDecimal = new BigDecimal("10");
System.out.println("aBigDecimal is valued at: " + aBigDecimal);

//Create an int and give it a value of 10
int anInt = 10;
System.out.println("anInt is valued at: " + anInt);

//Replace the values
aBigDecimal = new BigDecimal("100");
System.out.println("aBigDecimal has changed to: " + aBigDecimal);
anInt = 100;
System.out.println("anInt is valued at: " + anInt);

}
}

Examine the diagram for a visual representation of where each value is stored. Notice that we actually created two BigDecimals that each had different values even though we're only using a single identifier. Compare this to the int example where only one int is created, and the actual value of that int changes in the stack.

Recall that Strings are not a primitive data type, they are objects. Strings are actually immutable object as well. But unlike most other immutable objects, we don't need to use the new keyword every time we create or change a String. They behave much more like primitive data types when we use them in our code. This is because some magic trickery we're not going to get into right now is going on behind the scenes with Strings. You technically can use the new keyword to make a new String, but you shouldn't for reasons we'll discuss in a later chapter.

#### Copying BigDecimals

Since only the reference value is copied when we use the assignment operator, how do we go about copying BigDecimals? Most Classes in Java provide a copy constructor or a copy() method which returns a new copy of that object. Unfortunately BigDecimals are not one of these objects. There are several ways you could go about duplicating a BigDecimal. We will go over two options here.

The first option is to convert the original BigDecimal into a String, and then create a new BigDecimal using that String. The .toString() method can be used to convert a BigDecimal into a String. This is what's happening behind the scenes whenever we print out a BigDecimal (you can't add BigDecimals to the end of a String message so it's automatically converted using this method). We have to call the .toString in this scenario because it won't automatically convert the BigDecimal to a String in the argument for creating a new BigDecimal.

//Make original BigDecimal
BigDecimal original = new BigDecimal("500");
//Copy it into the BigDecimal named copy
BigDecimal copy = new BigDecimal(original.toString());
System.out.println(copy);
500

The above code is taking the original BigDecimal, getting the String "500" from it, and using that "500" to construct a new BigDecimal for copy. In this case, it's the functional equivalent of:

BigDecimal copy = new BigDecimal("500");

Another option is to call the add() method on the original BigDecimal using a value of zero. This will add nothing to the original BigDecimal and return a new BigDecimal with the same value as the original. You can access a BigDecimal with a value of zero with BigDecimal.ZERO. ZERO is a BigDecimal provided by the BigDecimal class with value 0 and scale 0.

BigDecimal original = new BigDecimal("500");
BigDecimal copy = original.add(BigDecimal.ZERO);

Using either of the above methods will generate a new BigDecimal with the equivalent value of the old one. Personally I think using the .add() method is the more elegant solution.

## 5.4: Equality and Relational Comparison Methods

As was demonstrated in Figure 5.3e and in the previous chapter, Java compares complex objects like Strings and BigDecimals by reference when we use the equality operator. We must use the .equals() method to compare the values of two BigDecimals rather than the equality operator ==.

Ex. 5.4a: BigDecimal Equality by Reference Variable
BigDecimal x = new BigDecimal("5");
BigDecimal y = new BigDecimal("5");

if (x==y){
System.out.println("They're equal.");
}
else{
System.out.println("They're not equal.");
}
They're not equal.

It says they're not equal because the BigDecimal x is pointing to a different object than BigDecimal y. They have the same value, but they're completely different objects in the heap.

When we use the .equals() method instead, it checks the contents.

Ex. 5.4b: BigDecimal Equality by Contents
if (x.equals(y)){
System.out.println("They're equal.");
}
else{
System.out.println("They're not equal.");
}
They're equal.

Now what about checking if one BigDecimal is larger or smaller than another? How do you do this?

We can use the .compareTo() method to check if one BigDecimal is greater or less than another. The compareTo method returns 1 if it's greater than, 0 if they're equal, or -1 if it's less than the BigDecimal in the method's argument.

Ex. 5.4c: BigDecimal Relational Comparisons
//Create BigDecimals for test
BigDecimal x = new BigDecimal("1000");
BigDecimal y = new BigDecimal("10000");
//Check if x is greater than y
if(x.compareTo(y) > 0){
System.out.println("x is greater than y");
}
//check if x is equal to y
else if(x.compareTo(y) == 0){
System.out.println("x is equivalent to y");
}
//check if x is less than y
else if(x.compareTo(y) < 0){
System.out.println("x is less than y");
}
x is less than y

Try changing the values of x and y in the above example to see how this behaves. You can also print out the compareTo() method itself and see it print out -1, 0, or 1 depending on the values you compare.

System.out.println(x.compareTo(y));

## 5.5: BigDecimal Scale & Rounding

BigDecimals consist of an unscaled precise integer value and an integer scale. For positive numbers, the scale is the amount of digits to the right of the decimal point. For example, take the number 123.456. In this case, the scale would be 3, as there are 3 digits after the decimal point.

The example diagram shows a BigDecimal holding a value of $$\pi$$ to 5 decimal places.

We can use the .setScale() method to set the scale of any BigDecimal. We can also specify a rounding mode in this method.

In order to use rounding modes, you must import the RoundingMode class from the API.

import java.math.RoundingMode;


The following example creates a BigDecimal, sets its scale to 2, and sets the rounding mode to round up to the next highest number in the event rounding is necessary.

Example 5.5a: Rounding Ceiling
BigDecimal x = new BigDecimal("13.556");
x = x.setScale(2, RoundingMode.CEILING);
System.out.println(x);
13.56

It outputs 13.56 because the 6 at the end is rounded up. RoundingMode.CEILING means round to the next highest number. There are several other RoundingModes you should be familiar with:

##### Fig. 5.5b. Rounding Modes
Rounding ModeDescriptionExample (Scale 1)
RoundingMode.UP Rounds up everything away from zero 1.01, 1.02, 1.05, and 1.08 all round to 1.1
RoundingMode.DOWN Rounds down towards zero 1.01, 1.02, 1.05, and 1.08 all round to 1.0
RoundingMode.CEILING Rounds towards positive infinity 1.01 is rounded to 1.1, -1.01 is rounded to -1.0
RoundingMode.FLOOR Rounds towards negative infinity 1.01 is rounded to 1.0, -1.01 is rounded to -1.1
RoundingMode.HALFUP Rounds to nearest 0, 5-9 rounds up, 1-4 rounds down. This is the way you were probably taught in school. 1.01 rounds to 1.0, 1.05 rounds to 1.1, 1.04 rounds to 1.0.
RoundingMode.HALFDOWN Rounds to nearest 0, 1-5 round down, 6-9 round up 1.01 rounds down to 1.0, 1.05 rounds down to 1.0, 1.06 rounds up to 1.1.
RoundingMode.HALFEVEN Rounds to the nearest even neighbour 1.05 rounds down to 1.0, but 1.15 rounds up to 1.2

Here is an example with all 7 rounding modes above:

Example 5.5c: All RoundingModes
BigDecimal x = new BigDecimal("1.05");

System.out.println("Round UP " + x.setScale(1, RoundingMode.UP));
System.out.println("Round DOWN " + x.setScale(1, RoundingMode.DOWN));
System.out.println("Round HALFUP " + x.setScale(1, RoundingMode.HALF_UP));
System.out.println("Round HALFDOWN " + x.setScale(1, RoundingMode.HALF_DOWN));
System.out.println("Round HALFEVEN " + x.setScale(1, RoundingMode.HALF_EVEN));
System.out.println("Round CEILING " + x.setScale(1, RoundingMode.CEILING));
System.out.println("Round FLOOR " + x.setScale(1, RoundingMode.FLOOR));
Round UP 1.1
Round DOWN 1.0
Round HALFUP 1.1
Round HALFDOWN 1.0
Round HALFEVEN 1.0
Round CEILING 1.1
Round FLOOR 1.0

You can also set the scale of a BigDecimal when you are first creating it.

BigDecimal someDecimal = new BigDecimal("12.3456").setScale(5, RoundingMode.CEILING);
System.out.println(someDecimal);

If you're dividing BigDecimals, you may actually be required to set a scale and rounding mode before doing a calculation or the program will error out. Look at the following example which attempts to divide two numbers:

BigDecimal x = new BigDecimal("10.42");
BigDecimal y = new BigDecimal("2.44");
BigDecimal quotient = x.divide(y);
System.out.println(quotient);
Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.

This error occurred because we did not tell the program how to round the number. It can't produce an exact result because $$10.42\div2.44$$ could be calculated to an infinite amount of decimal places. To solve this, you may add additional arguments to the .divide() method. In this case, we can specify a scale and RoundingMode as part of the divide arguments. Note that divide is the only method that works this way.

BigDecimal x = new BigDecimal("10.42");
BigDecimal y = new BigDecimal("2.44");
BigDecimal quotient = x.divide(y,5, RoundingMode.UP);
System.out.println(quotient);
4.27050

##### 5.5 - Try It Yourself

Directions: Create a program that calculates the total interest paid on a loan of $5000 after one year if the interest rate is 6.74 percent per year using BigDecimals. It should round the final answer to two digits after the decimal using RoundingMode.UP. ###### Solution: import java.math.BigDecimal; import java.math.RoundingMode; public class Main { public static void main(String[] args) { //Create BigDecimals BigDecimal loanAmount = new BigDecimal("5686.45"); BigDecimal interestRate = new BigDecimal("0.0674"); //Calculate Interest BigDecimal interestPaid = loanAmount.multiply(interestRate); interestPaid = interestPaid.setScale(2, RoundingMode.CEILING); //Print result System.out.println("You will pay$"+interestPaid+" in interest on your loan.");
}
}
You will pay $383.27 in interest on your loan. If you got a different answer, double check the rounding mode and scale you used. You should only be setting the scale to two for the final result, not the loan amount or the interest rate. ## 5.6: Creating BigDecimals from the Scanner You already know how to use Scanners to read user input, but what about BigDecimals? Thankfully, the Scanner already has a .nextBigDecimal() method we can use. Example 5.6a: Interest Calculator import java.math.BigDecimal; import java.math.RoundingMode; import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner input = new Scanner(System.in); //Ask for input System.out.println("Enter your loan amount:"); BigDecimal loanAmount = input.nextBigDecimal(); System.out.println("Enter your interest rate as a percentage:"); BigDecimal interestRate = input.nextBigDecimal(); //Remember to close scanner when done with it input.close(); //Calculate //Need to multiply interest rate by 0.01 to convert from percentage to decimal amount interestRate = interestRate.multiply(new BigDecimal("0.01")); BigDecimal interestPaid = loanAmount.multiply(interestRate); //Print Result System.out.println("You will pay$" + interestPaid.setScale(2,RoundingMode.UP) + " in interest on that loan.");

}
}
Enter your loan amount:
10000
Enter your interest rate as a percentage:
6.5
You will pay \$650.00 in interest on that loan.

Note on lines 11 and 13 there was no need to use the new keyword. The Scanner already returns a new BigDecimal for us. If you said BigDecimal loanAmount = new input.nextBigDecimal(); you would get a compile error.

BigDecimal provides some other methods we can use for mathematical calculations. These include methods for getting the absolute value, exponentiation, finding the square root, finding the remainder, and negating a number. These methods are .abs(), .pow(), .sqrt(), .remainder(), and .negate() respectively.

The following example shows all five of these methods in use. Pay attention to the comments, as some methods work slightly differently than others.

Example 5.7a: Other Calculations
import java.math.BigDecimal;
import java.math.MathContext;

public class Main {
public static void main(String[] args) {
//Create a BigDecimal to test some methods on
BigDecimal x = new BigDecimal("10");

//Find the absolute value
System.out.println("The absolute value of x is: " + x.abs());

//Find x raised to the 10th power - the pow() method requires an integer value
System.out.println("x to the 10th power is: " + x.pow(10));

//Find the square root, you must set a Math Context & import the MathContext class to use this
//The MathContext specifies certain rules related to the precision and rounding mode of the calculation
//You can read more about them in the Java API, DECIMAL32 is the simplest, least resource intensive option
System.out.println("The square root of x is: " + x.sqrt(MathContext.DECIMAL32));

//Find the remainder, you must provide a BigDecimal to divide by in the argument.
System.out.println("X divided by 3 has a remainder of :" + x.remainder(new BigDecimal("3")));

//Negating x makes 10 into -10
System.out.println("X negated is: " + x.negate());
}
}
The absolute value of x is: 10
x to the 10th power is: 10000000000
The square root of x is: 3.162278
X divided by 3 has a remainder of :1
X negated is: -10

##### 5.7 - Try It Yourself

Directions: Create a program that solves the following mathematical expression using BigDecimals. Use DECIMAL32 for any required MathContexts. Use a scale of 5 and RoundingMode.CEILING when dividing. Use a scale of 3 and RoundingMode.CEILING for your final answer.

$$y=\frac{32x+x^3}{\sqrt{9x-5}}$$ given $$x=3.456$$

There are multiple ways you can go about doing this. Do it in however many steps you'd like as long as you meet the above requirements. You can do all the calculations in one step, do them all in separate steps, or some combination of the both. When I did this, I chose to calculate the numerator and denominator separately, then divide them.

##### Solution:

In my example, I found the numerator and denominator separately, then divided them.

import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;

public class Main {
public static void main(String[] args) {

//Create a BigDecimal for x
BigDecimal x = new BigDecimal("3.456");

//Figure out the numerator

//Figure out the denominator
BigDecimal denominator = new BigDecimal("9").multiply(x).subtract(new BigDecimal("5")).sqrt(MathContext.DECIMAL32);
System.out.println(denominator);

BigDecimal result = numerator.divide(denominator, 5, RoundingMode.CEILING);
result = result.setScale(3, RoundingMode.CEILING);

//Print result
System.out.println("The result is: " + result);

}
}
The result is: 29.725

## Conclusion

In this section you learned all about BigDecimals, how to work with them, and how to do calculations using them. You also learned about the basics of where Java stores objects in memory and how it references those objects. Finally you learned about scale and rounding as it relates to BigDecimals. In the next section you will learn the basics of object-oriented design.

Assignment: There is no project assignment for this chapter. Your task is to go back and do the "Try It Yourself" exercises if you have not done so already. If you like, you may go back to the tax bracket calculator project from the last chapter, and modify it to work using BigDecimals instead of doubles.

### Related Guides

Chapter 4: Decision Making with Control Statements
You will learn how to use control statements (If/Else/Switches) to make decisions in Java. You'll also learn about the equals method and build a tax calculator.
Chapter 1: Introduction to Java
This section discusses key components of computers and how the Java programming language works. You will also learn about the tools developers use to code.
Chapter 3: Variables, Scanners & Strings
This chapter explains core Java concepts such as variables, data types, strings, and scanners to read user input.
Chapter 2: Hello, World.
This section introduces you to the IntelliJ IDE and your first Java project, which is called "Hello, World."
Chapter 6: Methods
This chapter discusses how to create your own methods, void methods, and return methods. You will also learn a little bit about scope.
Chapter 7: Loops
Learn how to use different loops in order to do repetitive tasks. The seventh free chapter of KG's Intro to Java series.