Ruby缺少常量表达式优化?

Ruby缺少常量表达式优化?,ruby,optimization,benchmarking,Ruby,Optimization,Benchmarking,我希望Ruby的解析器能够进行这种琐碎的优化,但似乎没有(说到YARV实现,Ruby 1.9.x,2.0.0): 需要“基准测试” def fib1 a、 b=0,1 而b

我希望Ruby的解析器能够进行这种琐碎的优化,但似乎没有(说到YARV实现,Ruby 1.9.x,2.0.0):

需要“基准测试”
def fib1
a、 b=0,1
而b<9999**4000
a、 b=b,a+b
结束
放入“\t立即!”
结束
最大纤维长度=9999**4000
def fib2
a、 b=0,1
而b
由于这两种方法都是相同的,只是在第二种方法中使用了预定义的常量而不是常量表达式,所以Ruby解释器似乎一次又一次地计算每个循环的功率常量

Ruby根本不做这个基本的优化,或者只是在某些特定情况下,有什么原因吗?

试试:

def fib1
  a, b = 0, 1
  while b < 9999**4000
    a, b = b, a+b
  end
  puts "\tdone !"
end


def fib2
  a, b = 0, 1
  value = 9999**4000
  while b < value
    a, b = b, a+b
  end
  puts "\tdone !"
end
def fib1
a、 b=0,1
而b<9999**4000
a、 b=b,a+b
结束
放入“\t立即!”
结束
def fib2
a、 b=0,1
值=9999**4000
而b<0
a、 b=b,a+b
结束
放入“\t立即!”
结束
不会有什么不同的

原因是,在第一个测试中,ruby在调用的方法中计算
9999**4000
,而第二个测试使用的是在外部(基准测试开始之前)计算的常量,因此,对于“9999**4000”计算时间,第二个结果更短

更新:事实上,这两个测试之间存在巨大差异,ruby很快就能计算出9999**4000,请参见下面的@JorgWMittag注释


我删除此答案不是为了保留评论。

很抱歉,我给出了另一个答案,但我不想删除或编辑我以前的答案,因为它下面有有趣的讨论

正如Jörg W Mittag所说,ruby每次都必须计算给定给
的表达式,而
,因为不可能说它是常数。作为一个极端的例子,我提出了以下代码:

class Fixnum
  alias :original_plus :+

  @@increment = 0
  def self.increase!
    @@increment = @@increment.original_plus 1
  end

  def +(other)
    (original_plus(other)).original_plus(@@increment)
  end 
end

while 1+1 < 5
  puts Fixnum.increase!
end
puts 'done' 

# 1 
# 2
# 3
# done
class-Fixnum
别名:original_plus:+
@@增量=0
自我提升!
@@增量=@@increment.original_加1
结束
def+(其他)
(原始添加(其他))。原始添加(@@increment)
结束
结束
而1+1<5
把Fixnum.increase放进去!
结束
完成
# 1 
# 2
# 3
#完成

问题的关键是,为什么提到的Ruby实现不会自动为您存储常量结果(优化),为什么您需要手动编写它。@DavidUnric-它会。问题在您的测试中。因为在循环的每次迭代过程中确定是否修改
Fixnum#**
以执行其他操作等同于解决停止问题。@BroiSatse问题是关于这样一个事实:如果缓存结果,则不必重新计算
9999**4000
,因为它在循环执行期间不会改变。一些语言/JIT将认识到这一点并优化循环。看到JRuby的结果会很有趣。重载不是问题。问题是Ruby允许重新定义内置操作符(或者换句话说,没有内置操作符)。静态地确定
1+1
的结果是什么根本不可能的,因为
Fixnum+
可能在运行时被重新定义。我认为Python不允许在运行时重新定义
int.\uuuu add\uuuuu
的含义。即使有可能,这肯定不会在解析器中完成,而是在优化器中完成。答案是:Ruby缺少适当的常量:-)有趣的是,如果我冻结
Fixnum
类,那么
**
就无法重新定义,Ruby的优化器忽略了这一点。同样地,
freeze
ing发生在运行时。同样,在编译时确定类是否被冻结相当于解决停止问题。另外,在运行时,你可以在猴子补丁<代码>对象y>冻结< />代码,所以你基本上只是用不同的方法重述了相同的问题:-为什么这个工作,比如在Scala或C++中或者类似的,是因为语言规范保证某些操作必须以某种方式运行,不能重新定义。这样,编译器编写人员就可以确保优化不会破坏任何东西。(实际上,C++和斯卡拉都要求在某些情况下进行优化,这不仅是优化,实际上是语言特征。
class Fixnum
  alias :original_plus :+

  @@increment = 0
  def self.increase!
    @@increment = @@increment.original_plus 1
  end

  def +(other)
    (original_plus(other)).original_plus(@@increment)
  end 
end

while 1+1 < 5
  puts Fixnum.increase!
end
puts 'done' 

# 1 
# 2
# 3
# done