The reason of such behaviour is that the string that is printed is the exact value - probably not what you expected, but that's the real value stored in memory - it's just a limitation of floating point representation.
According to javadoc, BigDecimal(double val) constructor behaviour can be unexpected if you don't take into consideration this limitation:
The results of this constructor can be somewhat unpredictable. One might assume that writing new BigDecimal(0.1) in Java creates a BigDecimal which is exactly equal to 0.1 (an unscaled value of 1, with a scale of 1), but it is actually equal to 0.1000000000000000055511151231257827021181583404541015625. This is because 0.1 cannot be represented exactly as a double (or, for that matter, as a binary fraction of any finite length). Thus, the value that is being passed in to the constructor is not exactly equal to 0.1, appearances notwithstanding.
So in your case, instead of using
double val = 77.48;
new BigDecimal(val);
use
BigDecimal.valueOf(val);
Value that is returned by BigDecimal.valueOf is equal to that resulting from invocation of Double.toString(double).
The reason of such behaviour is that the string that is printed is the exact value - probably not what you expected, but that's the real value stored in memory - it's just a limitation of floating point representation.
According to javadoc, BigDecimal(double val) constructor behaviour can be unexpected if you don't take into consideration this limitation:
The results of this constructor can be somewhat unpredictable. One might assume that writing new BigDecimal(0.1) in Java creates a BigDecimal which is exactly equal to 0.1 (an unscaled value of 1, with a scale of 1), but it is actually equal to 0.1000000000000000055511151231257827021181583404541015625. This is because 0.1 cannot be represented exactly as a double (or, for that matter, as a binary fraction of any finite length). Thus, the value that is being passed in to the constructor is not exactly equal to 0.1, appearances notwithstanding.
So in your case, instead of using
double val = 77.48;
new BigDecimal(val);
use
BigDecimal.valueOf(val);
Value that is returned by BigDecimal.valueOf is equal to that resulting from invocation of Double.toString(double).
It prints 47.48000 if you use another MathContext:
BigDecimal b = new BigDecimal(d, MathContext.DECIMAL64);
Just pick the context you need.
Double vs BigDecimal in financial programming
Use long or big decimal. Performance problems will most probably arise elsewhere before you factor a big decimal as the culprit
More on reddit.comStack overflow error after changing from double to BigDecimal in Java/OOP & Polymorphism
Everyone says that BigDecimal should be used when dealing with money but it’s much slower and takes more memory than double. I would think this would be especially important in high frequency low-latency applications like trading. Do people actually use BigDecimal in such systems or do they use doubles with some kind of workaround to handle the precision issue?
Edit: I do have experience working on trading and risk systems and I see doubles used much more often than BigDecimal so I was curious to see if this is more common in actual practice. Most of the systems I worked on only need precision to the penny so I wonder if that’s the reason?
Also, BigDecimal is a pain to use and code written with it look much uglier than plain doubles.
Hi, So after changing in program the Gross and netSalary to BigDecimal, I got lots of errors and it is not clear how I can fix them. So first of all in the main, I want to print the sum of all netSalaries paid, however when I changed it to BigDecimal it is saying that I cannot apply '+' to java.math.BigDecimal and I really can't find a solution for it. Secondly, my getEmployeeGrossSalary in the superclass RegularEmployees is highlighted and it says that the method recurses infinitely and can only end by throwing an exception and when I run the program I am getting a stackOverflow error because I am calling it in the main to print all salaries from highest to lowest, so why was everything fine when the type was double and how can I fix these errors? Thanks in advance!
import java.math.BigDecimal;
import java.math.RoundingMode;
public class RegularEmployees { //superclass
protected double employeeGrossSalary;
RegularEmployees(double employeeGrossSalary) {
this.employeeGrossSalary = employeeGrossSalary;
}
public BigDecimal employeeNetSalary() {
return new BigDecimal(this.employeeGrossSalary - (this.employeeGrossSalary * 0.1)).setScale(2,RoundingMode.DOWN);
}
public BigDecimal getEmployeeGrossSalary() { //the method here is highlighted and it says that getEmployeeGrossSalary recurses infinitely and can only end by throwing an exception.
return new
BigDecimal(String.valueOf(this.getEmployeeGrossSalary())).setScale(2,RoundingMode.DOWN);
}
}
import java.math.BigDecimal;
import java.math.RoundingMode;
public class ManagerEmployees extends RegularEmployees { //Subclass
private String managerDegree;
ManagerEmployees(double employeeGrossSalary, String managerDegree) {
super(employeeGrossSalary);
this.managerDegree = managerDegree;
public BigDecimal getEmployeeGrossSalary() {
return new
BigDecimal(String.valueOf(this.getEmployeeGrossSalary())).setScale(2,RoundingMode.DOWN);
}
@Override
public BigDecimal employeeNetSalary(){
return new BigDecimal(super.employeeGrossSalary - (super.employeeGrossSalary * 0.1)).setScale(2, RoundingMode.DOWN);
}
@Override
public BigDecimal getEmployeeGrossSalary() {
BigDecimal grossSalaryWithBonus = BigDecimal.valueOf(0.00);
if (this.managerDegree.equals("BSc")) {
grossSalaryWithBonus = new BigDecimal(super.employeeGrossSalary - (super.employeeGrossSalary * 0.1)).setScale(2, RoundingMode.DOWN);
} else {
if (this.managerDegree.equals("MSc")) {
grossSalaryWithBonus = new BigDecimal(super.employeeGrossSalary -(super.employeeGrossSalary * 0.2)).setScale(2, RoundingMode.DOWN);
} else {
if (this.managerDegree.equals("PhD")) {
grossSalaryWithBonus = new BigDecimal(super.employeeGrossSalary + (super.employeeGrossSalary * 0.35)).setScale(2, RoundingMode.DOWN);
}
}
}
return grossSalaryWithBonus;
}
}
import java.util.Comparator;
import java.util.ArrayList;
import java.math.BigDecimal;
public class Main { //main class
public static void main(String[] args){
ArrayList<RegularEmployees> employeesList = new ArrayList<>();
BigDecimal totalNetSalaries = BigDecimal.valueOf(0.00);
for (RegularEmployees currentEmployee : employeesList) {
totalNetSalaries = BigDecimal.valueOf(totalNetSalaries + currentEmployee.employeeNetSalary()); //Bug here ; Operator "+" cannot be applied to 'java.math.BigDecimal','java.math.BigDecimal' how can I fix it?
}
System.out.println(totalNetSalaries);
employeesList.sort(Comparator.comparing(RegularEmployees::getEmployeeGrossSalary).reversed());
for(RegularEmployees current : employeesList){
System.out.println(current.getEmployeeGrossSalary());
}