ruby 中的快速/快速整数乘法?
我正在尝试在 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 有没有快速的整数乘法?
I am trying to make a quick/efficient Mandelbrot implementation in Ruby. A long long time ago, one way to speed it up was using fixed point integers instead of floats.
So i made the following benchmark, comparing float and integer raising to a square, using multiplication or square ** operand.
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
and this generates the following output:
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)
which clearly shows the the Fixnum multiplication is almost twice as slow as floating point.
I have two questions:
- Can anyone explain this? A reason I can imagine is that Fixnum multiplication is slower because of the internal checking whether or not it needs to be converted to a Bignum.
- secondly is there than a quick integer multiplication for ruby?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我想到了一些事情。您没有指定您正在使用什么 Ruby 实现。由于您在 Windows 上运行 Ruby 1.8.6,因此我假设您使用的是通过 Windows 一键安装程序安装的 MRI。
这是最坏的情况:
以下是您可以尝试提高性能的一些技巧:
使用不同的 Ruby 实现:
-fast
命令行选项,与 Ruby 略有不兼容,但提高了性能,包括算术性能)和在后两种情况下,您可能需要稍微修改一下基准。两者最终都可以将 Ruby 代码编译为本机机器代码,但这可能需要一段时间。例如,JRuby 在方法执行 20 次后编译为 JVM 字节码,HotSpot Server 在执行 20000 次后将 JVM 字节码编译为本机机器代码。此外,编译本身也需要时间,因此程序需要运行一段时间才能通过提高性能来收回成本。
特别是,JRuby 首席开发人员之一 Charles Oliver Nutter 表示,根据工作负载,JRuby 可能需要 5-15 秒才能达到全速。你的基准测试大约快了 100 倍(这是你每天都不会听到的一句话......)。
A couple of things come to mind. You do not specify what Ruby implementation you are using. Since you run Ruby 1.8.6 on Windows, I am going to assume that you are using MRI installed via the Windows One-Click Installer.
This is kind of a worst-case scenario:
Here's a couple of tips that you could try to improve performance:
use a different implementation of Ruby:
-fast
commandline option, which is slightly incompatible with Ruby, but improves performance, including arithmetic performance) andIn the latter two cases you might want to revise your benchmarks a bit. Both eventually can compile Ruby code to native machine code, but it might take a while. JRuby for example compiles to JVM bytecode after a method has been executed 20 times and HotSpot Server compiles JVM bytecode to native machine code after it has executed 20000 times. Also, compilation itself takes time, so the program needs to run a while to gain back that cost through improved performance.
In particular, Charles Oliver Nutter, one of the JRuby lead developers, said that depending on the workload, JRuby might take up to 5-15 seconds to ramp up to full speed. Your benchmarks are about 100x too fast (here's a sentence you don't hear every day ...).
1.8.6 在这方面只是速度较慢。 1.8.7 做得更好一点,1.9.1 做得更好。我无法说出为什么,但 rvm 同意你和 Pavel 的观点,即 1.8.6 异常慢。
1.8.6 is just slower in this area. 1.8.7 does a little better and 1.9.1 does better still. I couldn't say why but rvm agrees with you and Pavel that 1.8.6 is oddly slow.
我无法解释你的表格。但我可以解释我的(ruby 1.8.7):
哎呀。整数乘法胜过浮点乘法。
由于你的处理器比我的处理器慢 5 倍(我将你的基准测试中的重复次数增加了十倍),所以一定有一些与 ruby 无关的东西。
**
运算可能使用浮点运算(exp(x*ln(2)),因此它和其他浮点运算一样慢。I can't explain your tables. But I can explain mine (ruby 1.8.7):
Whoops. Integer multiplication beats floating point ones.
Since your processor is 5 times slower than mine (I increased the number of repeats in your benchmark in ten times), there must be something not ruby-concerned.
**
operation probably used floating-point arithmetic(exp(x*ln(2)), so it is as slow as other floating-point operations.jruby 可能有更快的算术(或 1.9.x),也在 C 中执行(例如: http:// segment7.net/projects/ruby/inline_optimization.html )将明显有助于速度
jruby may have quicker arithmetic (or 1.9.x) also doing it in C (ex: http://segment7.net/projects/ruby/inline_optimization.html ) would help speeds obviously