Jest to związane z wewnątrzą reprezentacją liczb zmienno-przecinkowych. Możesz sobie przeczytać tu https://en.wikipedia.org/wiki/Floating_point#Accuracy_problems z czego wynika ten problem. Jeśli chcesz uzyskać precyzyjny wynik użyj klasy BigDecimal.
Masz tu kawałek kodu, z którego szybko załapiesz o co chodzi:
public static void main(String[] args) {
final double stala = 3.00;
final double stala1 = 3.14;
System.out.println("double: " + stala);
System.out.println("double1: " + stala1);
System.out.println("double sum: " + (stala1 + stala));
BigDecimal bigDecimalPi = BigDecimal.valueOf(3.14);
BigDecimal doublePi = new BigDecimal(3.14);
System.out.println(bigDecimalPi.setScale(100));
System.out.println(doublePi.setScale(100));
System.out.println(bigDecimalPi.setScale(100));
System.out.println(BigDecimal.valueOf(stala).setScale(100));
System.out.println(bigDecimalPi.add(BigDecimal.valueOf(stala)).setScale(100));
}
Zwróć uwagę na tworzenie bigDecimalPi oraz doublePi.