代码之家  ›  专栏  ›  技术社区  ›  nathanvda

Ruby中的快速/快速整数乘法?

  •  5
  • nathanvda  · 技术社区  · 15 年前

    我正在尝试在Ruby中快速/高效地实现Mandelbrot。很久以前,加快速度的一种方法是使用固定点整数而不是浮点数。

    所以我做了下面的基准,用乘法或平方**操作数将浮点数和整数升序比较为平方。

    require 'benchmark'
    
    Benchmark.bmbm(10) do |x|  
      x.report("float-multip") do
        for z in 0..100000 
          zf = z.to_f
          y = zf*zf
        end
      end  
    
      x.report("float-square") do
        for z in 0..100000 
          zf = z.to_f
          y = zf**2
        end
      end  
    
      x.report("int-multip") do
        zo = 0
        for zi in 0..100000 
          y2 = zo*zo
          zo += 1
        end
      end   
    
      x.report("int-multip") do
        for zi in 0..100000 
          y2 = zi**2
        end
      end  
    end
    

    并产生以下输出:

    Rehearsal ------------------------------------------------
    float-multip   0.125000   0.000000   0.125000 (  0.125000)
    float-square   0.125000   0.000000   0.125000 (  0.125000)
    int-multip     0.250000   0.000000   0.250000 (  0.250000)
    int-multip     0.282000   0.000000   0.282000 (  0.282000)
    --------------------------------------- total: 0.782000sec
    
                       user     system      total        real
    float-multip   0.110000   0.000000   0.110000 (  0.110000)
    float-square   0.125000   0.000000   0.125000 (  0.125000)
    int-multip     0.219000   0.016000   0.235000 (  0.235000)
    int-multip     0.265000   0.015000   0.280000 (  0.282000)
    

    这清楚地表明fixnum乘法的速度几乎是浮点的两倍。

    我有两个问题:

    • 有人能解释一下吗?我能想象的一个原因是fixnum乘法由于内部检查是否需要将其转换为bignum而变慢。
    • 第二,Ruby有没有比快速整数乘法更好的方法?
    4 回复  |  直到 13 年前
        1
  •  3
  •   Chuck Vose    15 年前

    1.8.6在该区域的速度较慢。1.8.7做得更好,1.9.1做得更好。我不知道为什么,但RVM同意你的观点,并且说1.8.6的速度非常慢。

    1.8.6: 
    Rehearsal ------------------------------------------------
    float-multip   0.140000   0.000000   0.140000 (  0.141560)
    float-square   0.150000   0.000000   0.150000 (  0.146286)
    int-multip     0.220000   0.000000   0.220000 (  0.223255)
    int-multip     0.180000   0.000000   0.180000 (  0.183850)
    --------------------------------------- total: 0.690000sec
    
    1.8.7:
    Rehearsal ------------------------------------------------
    float-multip   0.090000   0.000000   0.090000 (  0.092346)
    float-square   0.080000   0.000000   0.080000 (  0.080335)
    int-multip     0.070000   0.000000   0.070000 (  0.068012)
    int-multip     0.080000   0.000000   0.080000 (  0.081713)
    --------------------------------------- total: 0.320000sec
    
    1.9.1:
    Rehearsal ------------------------------------------------
    float-multip   0.070000   0.000000   0.070000 (  0.065532)
    float-square   0.080000   0.000000   0.080000 (  0.081620)
    int-multip     0.060000   0.000000   0.060000 (  0.065371)
    int-multip     0.070000   0.000000   0.070000 (  0.065761)
    --------------------------------------- total: 0.280000sec
    
        2
  •  5
  •   Jörg W Mittag    15 年前

    我想到了一些事情。您没有指定正在使用的Ruby实现。因为您在Windows上运行Ruby1.8.6,所以我假设您使用的是通过Windows一键安装程序安装的MRI。

    这是一种最坏的情况:

    1. mri是所有Ruby实现中速度最慢的
    2. Windows上的MRI是 更慢 而不是Linux或OSX上的MRI
    3. 一次点击安装程序使用来自RouyLang.Org的预编译二进制文件,它由微软Visual C++ 6从1996编译,因此 甚至更慢 用微软Visual C++ 10或GCC 4 .x或GCC 3×x编译的Windows上的MRI。

    以下是一些您可以尝试提高性能的提示:

    • 使用 RubyInstaller 项目,使用用GCC 3.x而不是MSVC6编译的解释程序,
    • 可能自己重新编译解释器(使用由 RubyInstaller 项目)使用GCC4.x和/或不同的优化选项(RubyInstaller使用中等优化选项编译,用于通用386 CPU)。
    • 使用比1.8.6新版本的MRI,
    • 使用不同的Ruby实现:

      • yarv明显快于mri(不幸的是,它只实现Ruby1.9,因此您可能需要更改代码)。
      • JRuby 在很多情况下,它都比yarv快得多,而且它实现了Ruby1.8和Ruby1.9(它还具有 -fast 命令行选项,它与Ruby稍微不兼容,但提高了性能,包括算术性能)和
      • IronRuby 也可能比yarv更快,这取决于工作负载。

    在后两种情况下,您可能需要稍微修改基准。两者最终都可以将Ruby代码编译为本机代码,但这可能需要一段时间。例如,jruby在方法执行20次之后编译为jvm字节码,hotspot服务器在执行20000次之后将jvm字节码编译为本机代码。此外,编译本身需要时间,因此程序需要运行一段时间,通过改进性能来收回成本。

    特别是,JRuby的主要开发人员之一CharlesOliverNutter说,根据工作负载的不同,JRuby可能需要5-15秒才能达到全速。你的基准测试太快了100倍(这是一个你每天都听不到的句子…)。

        3
  •  0
  •   P Shved    15 年前

    我不能解释你的桌子。但我可以解释我的(Ruby1.8.7):

                       user     system      total        real
    float-multip   0.600000   0.000000   0.600000 (  0.612311)
    float-square   0.650000   0.000000   0.650000 (  0.649399)
    int-multip     0.450000   0.010000   0.460000 (  0.457004)
    int-multip     0.690000   0.000000   0.690000 (  0.692879)
    

    哎哟。整数乘法胜过浮点乘法。

    因为您的处理器比我的慢5倍(我在基准测试中增加了10倍的重复次数),所以一定有一些与Ruby无关的东西。

    ** 操作可能使用浮点运算(exp(x*ln(2)),因此它和其他浮点运算一样慢。

        4
  •  0
  •   rogerdpack    13 年前

    JRuby可能有更快的算法(或1.9.x),也可以在C语言中执行(例如: http://segment7.net/projects/ruby/inline_optimization.html )显然有助于加速