Basicamente, é o seguinte: a conversão se dá com base não no range de valor, mas sim na capacidade de representação dos bits. Ou, em termos da especificação Java, magnitude versus precisão.
Quando se faz a conversão de long para float, ocorre perda de PRECISÃO, mas não de MAGNITUDE. Se seu número é 9,218868441522307072 * 10^18, sua magnitude é 9 * 10^18. Quando você faz a conversão para float, este tipo primitivo é plenamente capaz de armazenar a magnitue ( 10^18 ), mas incorre em perda de precisão, arredondando implicitamente o valor convertido para um que tenha a precisão mais próxima possível do original.
Assim, a “mágica” ocorre nos bits menos significativos, que são sacrificados:
Olhe o código abaixo e o resultado das linhas:
float f = 9218868441522307072L;
System.out.println(f); // resultado: 9.2188684E18
System.out.printf("%f", f); // resultado: 9218868437227405300,000000
Note que, no segundo exemplo, a partir do último bit significativo preciso exibido no primeiro exemplo, há perda de precisão, quando comparado com o original:
9218868[size=18] [color=red]4[/color][/size][telefone removido]
9.218868[size=18][color=red]4[/color][/size]E18
9218868[size=18][color=red]4[/color][/size][color=green][telefone removido][/color],000000 <-- note a perda de precisão (mas não de magnitude).