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.
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.
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.
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
.