2012-10-14 14 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

是的,我忘了提及它。 –

相关问题