Como você deve saber, existe diferença entre “precisão” e “exatidão”.
“Precisão” é a quantidade de dígitos, e “exatidão” é quão próximo está o resultado em relação ao resultado “real”.
O “double” é preciso no Java com a precisão de 15 dígitos, ou seja, se o número tiver mais de 15 dígitos (0,199.999.999.999.999.96 tem 17 dígitos - não me pergunte porque o Java mostra mais dígitos que a sua precisão), você tem de arredondar para 15 dígitos para ter o resultado mais exato (ou seja, 0,200.000.000.000.000).
Para você fazer contas matematicamente exatas, você não pode usar ponto flutuante, e se for só contas de soma, subtração, multiplicação e divisão, por incrível que pareça você também não pode usar java.lang.BigDecimal; você precisa construir uma clsse que lida com frações a partir de java.lang.BigInteger. Por exemplo, para obter o resultado “exato” de 1 - 3 * (1 / 3), que é 0, não é suficiente usar BigDecimal (como você deve saber, a divisão em BigDecimal de 1/3 gera uma exceção porque esse número gera uma dízima periódica; mas se você limitar a precisão a, por exemplo, 15 casas, então 1 - 3 * (1 / 3) volta o número 0,000.000.000.000.001 que não é zero como você estava esperando se o resultado fosse exato.