以下の内容はhttps://tech.guitarrapc.com/entry/2019/08/17/200200より取得しました。


PowerShell で1から100までの偶数の和を求めるワンライナー

PowerShellでどのようなやり方がいいかを少し考えてみます。

「1から100の偶数の和を求めるワンライナー」まとめ - Qiita

というのがあり、Twitterでつぶやいたのですが、一応まとめておきます。

guitarrapc_tech (@guitarrapc_tech) August 13, 2019

概要

リスト作ってもいいなら、メソッド方式で。作りたくないならパイプラインで。 bitwiseやシフト演算が最速と思いきや、普通に% (剰余) がいいです。

PowerShellでSIMD活用ってどうやるといいのかが気になります。

算出方法

どれでもどうぞ。

https://gist.github.com/guitarrapc/2c5049cc71699f2d6bb3b5006afbc6c3

いずれも求められますが、大きな違いは2つです。(8つあるのは、2 x 4通りです)

  • フィルター方法がパイプラインorメソッド
  • 偶数の算出が剰余(modulo) or除算(division) orビット演算(bitwise) orシフト演算(shift)

シーケンスの生成

フィルター方法の選択でメモリと実行速度に違いがでます。

  • パイプライン|を使うことで、1~100のメモリ域を確保しないので使用メモリが減る一方で、実行速度は落ちる
  • メソッド(シーケンス).Where{}を使うことで、1~100のメモリ域を確保するため使用メモリが増える一方で、実行速度は上がる

リスト作る必要ないならパイプラインがいいですね。

算出方法とベンチマーク

偶数の算出は、どれを選ぶかで実行速度に違いが出ます。

  • modulo

PowerShellでも算術演算子%を使えます。奇数は剰余が1、偶数は0です。 よく書きます。

  • bitwise

8ビットで考えます。奇数は20が常に1なので1とand(論理積)を演算すれば常に1になります。偶数なら0です。 こっちのほうが早い時には使います。

00000001
00000001   (00000001 is 1)
       &
--------
00000001

C系の(x & 1) == 0をPowerShellに翻訳すると($_ -band 1) -eq 0になります。

  • division

残術演算子/を使って2で割って、intで小数点を破棄してかけなおすと元に戻るかです。 明らかに無駄なので普段書きません。

  • shift

偶数の1ビット目が0であるため、右シフトして桁を落として左シフトで0を入れた時に元の値になれば偶数、そうでなく1少なくなれば奇数です。

00000011 (3)
00000001 (>> 1)
00000010 (<< 1)
--------
00000010 (2)

C系の((3 >> 1) << 1) == 3をPowerShellに翻訳すると(3 -shr 1) -shl 1 -eq 3となります。

速度を見てみましょう。計算回数が少なければ早いので、オペレータのコストとJITでの最適化がかかるかがポイントです。

PowerShellは1回1回のベンチマークのずれが激しいので、10000回実行した算術平均をとって1回当たりの実行速度を見てみます。*1

BenchMark(Method) Times Avg(ms)
bitwise 1000 0.542
division 1000 0.521
modulo 1000 0.489
shift 1000 0.520
Benchmark(Pipeline) Times Avg(ms)
bitwise 1000 1.353
division 1000 1.486
modulo 1000 1.330
shift 1000 1.359

https://gist.github.com/guitarrapc/04df00c23ca58f276fd694b41b87b27a

余談 : クラス構文

PowerShellでは、同じ処理でもクラス構文にすると、dllからの呼び出しになるため高速化する傾向があります。

といっても、偶数判定だけクラス構文にすると遅くなります。

Benchmark(Method) Times Avg(ms)
shift 1000 1.287
class 1000 1.088

https://gist.github.com/guitarrapc/07809ddbefadbbb266570bddaa291d56

全体をクラス構文にして、インスタンスメソッド、スタティックメソッドでどうなるか見てみると早くなっていないことがわかります。

Benchmark(Class) Times Avg(ms)
bitwise 1000 0.536
division 1000 0.562
modulo 1000 0.533
shift 1000 0.559
Benchmark(Static) Times Avg(ms)
bitwise 1000 0.538
division 1000 0.553
modulo 1000 0.521
shift 1000 0.544

https://gist.github.com/guitarrapc/2eb9005aa441b217a2d99f6e90ddacb9

この程度だと速度差つかないですね。(PowerShell 5.1 / 6.2)

*1:これでも差が出るのでウォームアアップがあるとよりいいですね




以上の内容はhttps://tech.guitarrapc.com/entry/2019/08/17/200200より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14