Ruby 3.0 makes x ** 2 faster

x ** 2 is slow

Suppose the variable x contains a number such as an Integer or Float. The calculation of the square of x is

x ** 2

But if you want to calculate as fast as possible

x * x

You should write. The latter is by far the fastest. Or rather, the former is slow.

Benchmark test

First

gem install benchmark_driver

Then install benchmark_driver and install it.

square.yaml


prelude: |
  x = 3.0
benchmark:
  - "x ** 2"
  - "x * x"

Prepare a YAML file called

benchmark-driver square.yaml

You can compare it with.

When I measured it with ruby 2.7.1p83 (2020-03-31 revision a0c7c23c9c) [x86_64-darwin17], the result is as follows.

     x * x:  92940175.9 i/s 
    x ** 2:  15605744.0 i/s - 5.96x  slower

Wow!

Well, even if it's slow, it can be executed 15 million times per second, so this slowness is a problem only when doing a lot of numerical calculations [^ sp].

[^ sp]: When you want to speed up a program, it is important to follow the numbers properly by performing benchmark tests, and it is meaningless to raise the bloodline to optimize the part that does not affect the execution time of the entire program I want to keep in mind.

Improved with Ruby 3.0

Changes have been made to treat ** 2 specially for Float and calculate faster. You can check it with Ruby 3.0.0-preview1.

If you have Ruby in rbenv, you can easily test it with benchmark_driver. For the same YAML file as before, this time

benchmark-driver square.yaml --rbenv "2.7.2;3.0.0-preview1"

And. The results are as follows.

                       x ** 2
  3.0.0-preview1:  37039739.4 i/s 
           2.7.2:  16010580.7 i/s - 2.31x  slower

                        x * x
           2.7.2:  91881050.6 i/s 
  3.0.0-preview1:  88138626.5 i/s - 1.04x  slower

x * x, rather 3.0.0-preview1 is slower, but this is within the margin of error. x ** 2 is 2.3 times faster.

Impressions

Well, x * x is still more than twice as fast as x ** 2, but I think it's still an important evolution. There are a lot of codes out there like x ** 2 and they make it faster without doing anything.

In some cases, you may want to use ** 2 at the expense of speed. That's when the variable you want to square isn't in an expression. Well, I think this is the image:

items.map.with_index{ |item, i| (a * item.value + b[i]) ** 2 }

this

items.map.with_index{ |item, i| (a * item.value + b[i]) * (a * item.value + b[i]) }

Not only is it redundant, but it probably slows it down. So, once you put the value of the expression in a variable

items.map.with_index{ |item, i| x = a * item.value + b[i]; x * x }

Will be written. If speed is the highest priority, I would write it like this, but if you say "I want speed but I also want simplicity", I might use ** 2.

Recommended Posts

Ruby 3.0 makes x ** 2 faster
Gem list of each ruby version 2.5.x
[Java] Make programs 10x faster with parallelStream
CentOS8.2 (x86_64) + ruby2.5 + Rails5.2 + MariaDB (10.3.17) environment construction