- Chapter 5: BigDecimals, Mutability & 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);
Code language: JavaScript (javascript)
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;
Code language: CSS (css)
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");
Code language: JavaScript (javascript)
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);
}
}
Code language: JavaScript (javascript)
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");
BigDecimal sum = aDecimal.add(bDecimal);
System.out.println(sum);
Code language: JavaScript (javascript)
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 sum = x.add(y);
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);
Code language: JavaScript (javascript)
The sum is 7
The difference is 3
The product is 10
The quotient is 2.5
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.
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. To keep this section relatively simple, we will only focus 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, look at this 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.");
}
}
}
Code language: JavaScript (javascript)
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);
}
}
Code language: JavaScript (javascript)
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);
}
}
Code language: JavaScript (javascript)
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);
}
}
Code language: JavaScript (javascript)
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.
To learn more about Java being pass-by-value, check out this article: Java is Pass-By-Value, Damnit!
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);
}
}
Code language: JavaScript (javascript)
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);
Code language: JavaScript (javascript)
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");
Code language: JavaScript (javascript)
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);
Code language: JavaScript (javascript)
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.");
}
Code language: JavaScript (javascript)
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.");
}
Code language: JavaScript (javascript)
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");
}
Code language: JavaScript (javascript)
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));
Code language: Java (java)
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;
Code language: CSS (css)
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);
Code language: JavaScript (javascript)
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 Mode | Description | Example (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));
Code language: JavaScript (javascript)
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);
Code language: JavaScript (javascript)
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);
Code language: JavaScript (javascript)
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);
Code language: JavaScript (javascript)
4.27050
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.
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.");
}
}
Code language: JavaScript (javascript)
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.
5.7: Additional BigDecimal Calculations
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());
}
}
Code language: JavaScript (javascript)
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
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.
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.