2012-10-14 47 views
8

我正在將一些C代碼移植到Scala中,它廣泛使用了浮點運算。我在斯卡拉寫了下面的代碼基礎上的C版複製/粘貼:爲什麼添加括號會改變這個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) 

這個計算結果稍微偏離一下C版生產。但是,如果我將括號括起來,如下所示:

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

結果值完全匹配C版本。當括號內有括號時,操作的順序似乎不同,但我不明白爲什麼會有所不同。任何想法這裏發生了什麼?

+1

奇怪。一個錯誤?你爲什麼不嘗試逐漸簡化表達式,直到得到最簡單的表達式,從而導致差異?例如'2640.96e-6 * sin(f5)+ 63.52e-6 * sin(2.0 * f5)'會產生差異嗎?如果刪除第一學期的係數會怎樣? –

+1

(你也可以試着看看發出的字節碼,它聽起來不像看起來那麼嚇人,它不像看x86彙編器(雖然承認它並不遙遠),儘管首先得到一個簡單的表達式,所以字節碼是相對的簡而言之,我懷疑這與推斷的complimentaryTerms類型有關。 –

+0

(嗯,你也可以試試'println complimentaryTerms.getClass()',看看它是否相同。 –

回答

14

這是因爲分號推理。樣品(//; - 推斷出分號):

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

並用括號:

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

或者有拖尾 「+」:

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

分號推斷
規則 行結束符被視爲分號,除非o下列條件NE是真的:

  1. 有問題的線,將不合法的聲明,結束如句號或綴操作一句話結束。

  2. 下一行以無法啓動語句的單詞開頭。

  3. 行在括號(...)或括號[...]內結束,因爲無論如何這些行不能包含多個語句。

+0

看起來很棒,規則聽起來很合理,但是......這個bug完全不明顯,我猜想它會變得明顯你碰到這個bug嗎? –

+2

它也不會出錯,因爲有'unary_ +'和'unary_-'方法,即'+ 1.1'是一個有效的表達式,但是(例如)'* 1.1' isn 't。 –

+0

是的,我忘了提及它。 –

相關問題