Powiel możliwe:
Retain precision with Doubles in javaJava podwójnej precyzji ze stałym mnożenie/dzielenie
Znasz różnicę między tymi dwoma procesami w Javie.
final double m1 = 11d/1e9; // gives 1.1e-8
final double m2 = 11d * 1e-9; // gives 1.1000000000000001e-8
Widzę w wygenerowanym kod bajtowy, że prekompilowany wynik m2 już nie jest tym, czego się spodziewałem.
W wyjściu javap -verbose -c
widzę następującą wartość:
const #3 = double 1.1E-8d;
[...]
const #6 = double 1.1000000000000001E-8d;
Gdy używam m1 lub m2 w innych wyrażeń, nie mam ten sam rezultat.
Kiedy próbuję to samo w C, M1 i M2 jest ściśle 1.1E-8
Myślę, że mój problem jest w sposób java obsługuje podwójnej precyzji obliczeń, ale nie mogę wytłumaczyć co tęsknię.
OK, to jest wyjaśnienie dla Javy, ale teraz dlaczego po uruchomieniu tego samego kodu w C mam całą precyzję, której potrzebowałem? – Joker
Kompilator C zoptymalizuje kod * znacznie * dalej niż "javac". Może to oznaczać, że może przetłumaczyć '/ 1e-9' na' * 1e9', ponieważ a) jest szybszy i b) dokładniejszy.Kompilator Java ma bardzo mało optymalizacji, pozostawia to JIT, co oznacza również, że zoptymalizowany i zoptymalizowany kod musi zrobić to samo, w przeciwnym razie zobaczyłbyś zmianę zachowania podczas działania programu. Konwersja "podwójnego" do łańcucha jest również inna w językach C i Java, ale mniej prawdopodobne jest, że będzie przyczyną tej różnicy. W obu przypadkach używają tej samej jednostki FPU. –
Również kompilator języka C może skorzystać z 80-bitowych rejestrów zmiennoprzecinkowych/obliczeń, które posiada komputer. Jest to zależne od platformy i jest dostępne tylko w procesorach x86/x64. Java będzie zachowywać się tak samo na każdej platformie, więc użyje tylko 64-bitowego zmiennoprzecinkowego, nawet jeśli dostępny jest 80-bitowy zmiennoprzecinkowy. –