2012-10-14 12 views
8

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?

+1

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? –

+1

(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: –

+0

(Hmmm, możesz też wypróbować 'println complimentaryTerms.getClass()' i sprawdzić czy jest taki sam czy nie –

Odpowiedz

14

Jest to spowodowane wnioskiem średnika. Próbkę (//; - wywnioskować średnik):

val x = 1 //; 
     + 1 //; 
println(x) // 1 

I z nawiasami:

val x = (1 
     + 1) //; 
println(x) // 2 

Albo z ogonków "+":

val x = 1 + 
     1 //; 
println(x) // 2 

Zasady średnik wnioskowania
Zakończenie linii jest traktowane jako średnik, chyba że ne z następujących warunków:

  1. Linia w pytaniu kończy się słowem, które nie byłyby legalne w końcu oświadczenie, takie jak okres lub operatora Infix.

  2. Następna linia zaczyna się od słowa, które nie może rozpocząć wyciągu.

  3. Wiersz kończy się w nawiasach (...) lub nawiasach [...], ponieważ i tak nie może zawierać wielu instrukcji.

+0

Dobrze zauważona, a zasada brzmi tak rozsądnie ... A jednak ... ten błąd jest całkowicie nieoczywisty. kiedy natkniesz się na ten błąd? –

+2

To również nie powoduje błędu, ponieważ istnieją metody 'unary_ +' i 'unary_-', tj. fakt, że '+ 1.1' jest poprawnym wyrażeniem, ale (na przykład)' * 1.1' isn t. –

+0

Tak, zapomniałem o tym wspomnieć. –

Powiązane problemy