La "f" al final de los valores definidos como float nos indica que es una variable de tipo flotante, en el caso de las variables definidas como double hay dos opciones para identificarlos, ya sea por que contienen una d al final de su valor o porque no tienen ninguna letra.
Pasando a la siguiente pregunta concerniente a la inconsistencia del valor de la variable total puedo decirte que los tipos primitivos float y double en Java son números de coma flotante, donde el número se almacena como una representación binaria de una fracción y un exponente.
Más específicamente, un valor de punto flotante de precisión doble como el doubletipo es un valor de 64 bits, donde:
1 bit denota el signo (positivo o negativo).
11 bits para el exponente.
52 bits para los dígitos significativos (la parte fraccionaria como binaria).
Estas partes se combinan para producir una double representación de un valor.
Para obtener una descripción detallada de cómo se manejan los valores de coma flotante en Java, consulte la https://docs.oracle.com/javase/specs/jls/se8/html/jls-4.html#jls-4.2.3.
Los tipos byte, char, int, son números de punto fijo , que son representaciones exactas de números. A diferencia de los números de punto fijo, los números de punto flotante algunas veces (es seguro asumir que "la mayoría de las veces") no podrán devolver una representación exacta de un número. Esta es la razón por la que terminas como resultado de 0.30000000000000004.
Cuando requiera un valor que sea exacto, como 1.5 o 150.1005, querrá usar uno de los tipos de punto fijo, que podrá representar el número exactamente. Java tiene una clase BigDecimal que manejará números muy grandes y números muy pequeños.
Para resumir estos problemas se presentan por la forma en que Java maneja los valores de Punto Flotante.
Un saludo!