【问题标题】:quick/fast integer multiplication in ruby?ruby 中的快速/快速整数乘法?
【发布时间】:2009-11-24 18:12:30
【问题描述】:

我正在尝试在 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​​ 是否有快速整数乘法?

【问题讨论】:

  • 分配可能会使您的速度减慢千分之几或百分之一秒。 (IE,必须在测试中监控和清理的未使用范围,不像y那样使用。)

标签: ruby multiplication mandelbrot


【解决方案1】:

我想到了几件事。您没有指定您正在使用的 Ruby 实现。由于您在 Windows 上运行 Ruby 1.8.6,因此我假设您使用的是通过 Windows One-Click Installer 安装的 MRI。

这是最坏的情况:

  1. MRI 是所有 Ruby 实现中最慢的
  2. Windows 上的 MRI甚至比 Linux 或 OSX 上的 MRI 慢
  3. 一键式安装程序使用来自 Ruby-Lang.Org 的预编译二进制文件,这些二进制文件从 1996 年开始使用 Microsoft Visual C++ 6.0 编译,因此在 Windows 上比使用 MRI 编译的速度甚至更慢 Microsoft Visual C++ 10.0 或 GCC 4.x 甚至 GCC 3.x。

您可以尝试以下几个技巧来提高性能:

  • 使用RubyInstaller 项目,该项目使用使用 GCC 3.x 而不是 MSVC6 编译的解释器,
  • 也许你自己重新编译解释器(使用RubyInstaller 项目提供的 Rakefile 并不难)使用 GCC 4.x 和/或不同的优化选项(RubyInstaller 使用适度的优化选项和通用 386 CPU 编译),
  • 使用比 1.8.6 更新的 MRI 版本,
  • 使用不同的 Ruby 实现:

    • YARV 比 MRI 快得多(不幸的是,它只实现了 Ruby 1.9,因此您可能需要更改代码),
    • JRuby 在很多场景中都比 YARV 快得多,它同时实现了 Ruby 1.8 和 Ruby 1.9(它还有一个 -fast 命令行选项,它与 Ruby 略有不兼容,但提高了性能,包括算术性能)和
    • IronRuby 也可能比 YARV 更快,具体取决于工作负载。

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

特别是 JRuby 的主要开发人员之一 Charles Oliver Nutter 表示,根据工作负载,JRuby 可能需要 5-15 秒才能加速到全速。您的基准测试速度快了大约 100 倍(这是您每天都不会听到的一句话……)。

【讨论】:

  • 是的,我还在这篇文章中看到:antoniocangiano.com/2009/08/10/how-much-faster-is-ruby-on-linux linux 上的 ruby​​ 也快得多(ruby 1.9.1 为 70%,ruby 1.8.6 为 100%)。所以我要做的是将我所有的代码移到 1.9.1,希望我的大多数 gems/plugins 是兼容的。有两个兼容性需要担心:一方面是 ruby​​ 1.9.1,另一个是来自 ruby​​ 安装程序的二进制平台。但我认为这将是非常值得的努力。另一方面,我将在我机器上的虚拟机中在 linux 上对其进行测试,也许这会更快;)
【解决方案2】:

1.8.6 在这方面速度较慢。 1.8.7 稍微好一点,1.9.1 做得更好。我不能说为什么,但 rvm 同意你和 Pavel 的观点,即 1.8.6 慢得奇怪。

1.8.6: 排练------------------------------------------------ 浮点乘法 0.140000 0.000000 0.140000 (0.141560) 浮点平方 0.150000 0.000000 0.150000 ( 0.146286) 整数倍数 0.220000 0.000000 0.220000 (0.223255) 整数倍数 0.180000 0.000000 0.180000 (0.183850) --------------------------------------- 总计:0.690000 秒 1.8.7: 排练------------------------------------------------ 浮点乘法 0.090000 0.000000 0.090000 (0.092346) 浮点平方 0.080000 0.000000 0.080000 ( 0.080335) 整数倍数 0.070000 0.000000 0.070000 (0.068012) 整数倍数 0.080000 0.000000 0.080000 (0.081713) --------------------------------------- 总计:0.320000 秒 1.9.1: 排练------------------------------------------------ 浮点乘法 0.070000 0.000000 0.070000 (0.065532) 浮点平方 0.080000 0.000000 0.080000 ( 0.081620) 整数倍数 0.060000 0.000000 0.060000 (0.065371) 整数倍数 0.070000 0.000000 0.070000 (0.065761) --------------------------------------- 总计:0.280000 秒

【讨论】:

  • 哇太棒了。我整天都在看基准。我会尽快迁移到 1.9.1 :)
  • 1.9.1 仍然不稳定,并且对代码进行了一些重大更改。它是 2.0 之前的分支,因此您可能会发现很多有趣的差异。我不确定这对你的情况是否重要,但如果你正在做生产代码 1.9.1 可能不是最好的。另一方面,学术界...... :)
【解决方案3】:

我无法解释您的表格。但我可以解释一下我的(ruby 1.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)),所以它和其他浮点运算一样慢。

【讨论】:

  • 关于 :) 我在 Windows 上运行 ruby​​ 1.8.6,所以也许这可以解释问题。打算在虚拟盒子里试试:)
  • 确实,较慢的整数平方有点引人注目。对于 JRuby,整数平方实际上比浮点平方慢。
【解决方案4】:

jruby 可能有更快的算术(或 1.9.x),也可以在 C 中执行(例如:http://segment7.net/projects/ruby/inline_optimization.html)显然有助于提高速度

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-01-01
    • 2011-04-10
    • 2017-01-25
    • 1970-01-01
    • 2021-12-03
    • 1970-01-01
    • 2011-11-30
    • 2015-03-02
    相关资源
    最近更新 更多