Przenoszę kod C do Scali, który szeroko wykorzystuje arytmetykę zmiennoprzecinkową. Napisałem następujący kod w Scala oparta na kopiuj/wklej w wersji C:Dlaczego dodanie otaczających nawiasów zmienia wynik tego wyrażenia Scala?
val complimentaryTerms = 2640.96e-6 * sin (f5)
+ 63.52e-6 * sin (2.0 * f5)
+ 11.75e-6 * sin (2.0 * f3 - 2.0 * f4 + 3.0 * f5)
+ 11.21e-6 * sin (2.0 * f3 - 2.0 * f4 + f5)
- 4.55e-6 * sin (2.0 * f3 - 2.0 * f4 + 2.0 * f5)
+ 2.02e-6 * sin (2.0 * f3 + 3.0 * f5)
+ 1.98e-6 * sin (2.0 * f3 + f5)
- 1.72e-6 * sin (3.0 * f5)
- 0.87e-6 * t * sin (f5)
Wynik tego obliczenia jest nieco od tego, co wersja C produkuje. Jeśli jednak dołączę wyrażenie w nawiasach, to:
val complimentaryTerms = (2640.96e-6 * sin (f5)
+ 63.52e-6 * sin (2.0 * f5)
+ 11.75e-6 * sin (2.0 * f3 - 2.0 * f4 + 3.0 * f5)
+ 11.21e-6 * sin (2.0 * f3 - 2.0 * f4 + f5)
- 4.55e-6 * sin (2.0 * f3 - 2.0 * f4 + 2.0 * f5)
+ 2.02e-6 * sin (2.0 * f3 + 3.0 * f5)
+ 1.98e-6 * sin (2.0 * f3 + f5)
- 1.72e-6 * sin (3.0 * f5)
- 0.87e-6 * t * sin (f5))
wynikowa wartość pasuje dokładnie do wersji C. Wygląda na to, że kolejność operacji musi być inna, gdy istnieją nawiasy klamrowe, a gdy nie, ale nie rozumiem, dlaczego miałoby to jakieś znaczenie. Masz pojęcie, co się tutaj dzieje?
Dziwne. Błąd? Dlaczego nie próbujesz stopniowo upraszczać wyrażenia, dopóki nie uzyskasz najprostszego wyrażenia dającego rozbieżność? np. "2640.96e-6 * sin (f5) + 63,52e-6 * sin (2.0 * f5)" podać rozbieżność? Co się stanie, jeśli usuniesz współczynnik pierwszego terminu? –
(Można również spróbować spojrzeć na emitowany kod bajtowy.To nie jest tak straszne, jak się wydaje.To nie jest tak, jak patrząc na asembler x86 (choć wprawdzie nie jest daleko) Spróbuj najpierw uzyskać prostą ekspresję, więc kod bajtowy jest stosunkowo Krótko, podejrzewam, że ma to coś wspólnego z wywnioskowanym typem freeTerms: –
(Hmmm, możesz też wypróbować 'println complimentaryTerms.getClass()' i sprawdzić czy jest taki sam czy nie –