Du kennst sicherlich die Darstellung von ganzen Zahlen: Man hat die Zweierpotenzen 1, 2, 4, 8, 16, 32, 64 usw. zur Verfügung und summiert diese, um eine Zahl darzustellen. Beispielsweise ist 19 = 16 + 2 + 1.
Bei Dezimalzahlen hat man nun binäre Brüche: 1/2, 1/4, 1/8, 1/16, 1/32, 1/64 usw.
0.4 entspricht nun dem Bruch 2 / 5. Wenn wir 1/2 nähmen, wäre das zu viel, also ist das erste Bit eine Null. 1/4 ist kleiner, also nehmen wir die - das zweite Bit ist eine 1 und es verbleiben noch 3/20. Wenn man das jetzt so weitermacht, kommt man nie zum Ende - es handelt sich um einen periodischen Bruch. Sowas wie 7/6 im Dezimalsystem, das ist auch nicht darstellbar und wird deshalb lieber als Bruch geschrieben. Das machen floats aber nicht so, sonst könnte man ja nur rationale, aber keine reellen Zahlen darstellen. Deshalb darf man floats auch nicht mit == vergleichen. Es gibt da sehr viele, schöne Beispiele, in denen das kaputtgeht, weil als gleich empfundene Zahlen intern anders berechnet wurden, die Darstellung in einem Bit abweicht und deshalb keine Gleichheit im Sinne von Java vorliegt.
Aus diesem Grund vermeidet man floats für alles, wo Genauigkeit einigermaßen wichtig ist, beispielsweise bei Banken. Dort rechnet man in Centbeträgen und nicht in dezimalen Euros. Das gleiche trifft natürlich auch für doubles zu.
Hier ist ein kleiner Rechner, wo du das mal testen kannst:
IEEE 754 Converter