2012-10-14 8 views
8

Sto eseguendo il porting di un codice C su Scala, che utilizza ampiamente l'aritmetica in virgola mobile. Ho scritto il seguente codice a Scala sulla base di una copia/incolla della versione C:Perché l'aggiunta di parentesi che racchiude cambia il risultato di questa espressione di 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) 

Il risultato di questo calcolo è un po 'fuori da quello che la versione C produce. Tuttavia, se allego l'espressione tra parentesi, in questo modo:

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)) 

il valore risultante corrisponde esattamente la versione C. Sembra che l'ordine delle operazioni debba essere diverso quando ci sono parentesi che racchiudono contro quando non ce ne sono, ma non capisco perché ciò possa fare la differenza. Qualche idea su cosa sta succedendo qui?

+1

Strano. Un insetto? Perché non provi a semplificare gradualmente l'espressione fino a ottenere l'espressione più semplice che dia una discrepanza? per esempio '2640.96e-6 * sin (f5) + 63.52e-6 * sin (2.0 * f5)' diamo una discrepanza? Cosa succede se si rimuove il coefficiente del primo termine? –

+1

(Puoi anche provare a guardare il codice by emesso. Non è così spaventoso come sembra. Non è come guardare l'assembler x86 (anche se ammette che non è lontano). Cerca di ottenere un'espressione semplice prima però, quindi il bytecode è relativamente Insomma, ho il sospetto che sia qualcosa che ha a che fare con il tipo inferito di Temi complementari –

+0

(Hmmm, potresti anche provare 'println complimentaryTerms.getClass()', e vedere se è lo stesso o no. –

risposta

14

È a causa dell'inferenza del punto e virgola. Esempio (//; - dedotto e virgola):

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

E con parentesi:

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

O con tailing "+":

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

Le regole di inferenza e virgola
Una fine di riga viene trattata come un punto e virgola a meno che o na delle seguenti condizioni è vero:

  1. La linea in questione termina in una parola che non sarebbe legale come la fine di una dichiarazione, come ad esempio un periodo o un operatore infisso.

  2. La riga successiva inizia con una parola che non può iniziare un'istruzione.

  3. La linea termina tra parentesi (...) o parentesi [...], poiché non possono comunque contenere più istruzioni.

+0

Ben avvistato. E la regola suona così ragionevole.Eppure .... questo bug è totalmente non ovvio. Suppongo che diventa ovvio il secondo tempo si incontra questo bug? –

+2

Non ha errori anche perché ci sono metodi 'unary_ +' e 'unary_-', cioè il fatto che '+ 1.1' è un'espressione valida ma (per esempio)' * 1.1' isn 't –

+0

Sì, ho dimenticato di parlarne. –

Problemi correlati