12

Double次のコードは、型の数を型の 1 つに切り捨てますWord16(他の単語の型も同様に動作すると思われますが、例として 1 つを選択する必要がありました)。

truncate1 :: Double -> Word16
truncate1 = fromIntegral . (truncate :: Double -> Int)

ご覧のとおり、最初に に切り捨ててからInt、 にキャストしWord16ます。この関数を直接の切り捨てに対してベンチマークしました。

truncate2 :: Double -> Word16
truncate2 = truncate

驚いたことに、最初のバージョン (最初にInt型を調べたもの) の方がパフォーマンスがはるかに優れていました。または2番目はさらに悪い。基準出力によると:

benchmarking truncate/truncate1
mean: 25.42399 ns, lb -47.40484 ps, ub 67.87578 ns, ci 0.950
std dev: 145.5661 ns, lb 84.90195 ns, ub 244.2057 ns, ci 0.950
found 197 outliers among 100 samples (197.0%)
  97 (97.0%) low severe
  100 (100.0%) high severe
variance introduced by outliers: 99.000%
variance is severely inflated by outliers

benchmarking truncate/truncate2
mean: 781.0604 ns, lb 509.3264 ns, ub 1.086767 us, ci 0.950
std dev: 1.436660 us, lb 1.218997 us, ub 1.592479 us, ci 0.950
found 177 outliers among 100 samples (177.0%)
  77 (77.0%) low severe
  100 (100.0%) high severe
variance introduced by outliers: 98.995%
variance is severely inflated by outliers

正直、Criterion は使い始めたばかりなので、使い慣れていません25.42399 nsが、 よりも短い実行時間であることは理解してい781.0604 nsます。ここで何らかの専門化が役割を果たしているのではないかと思います。truncate2遅すぎませんか?その場合、truncate改善できますか?さらに、もっと速い方法を知っている人はいますか? あまり使っていない型に何か間違ったキャストをしたい気がします。

前もって感謝します。

私は GHC-7.4.2 でコンパイルしており、最適化が有効になっています ( -O2)。

4

1 に答える 1

13

GHC.Word まず、モジュールには次の RULEプラグマが含まれていることに注意してください。

"truncate/Double->Word16"
    forall x. truncate (x :: Double) = (fromIntegral :: Int -> Word16) (truncate x)

これは、提供する最適化を正確に実行するための簡単な書き換えルールtruncate1です。そのため、考慮すべきいくつかの質問があります。

なぜこれが最適化なのですか?

のデフォルトの実装truncateは汎用であるため、あらゆるIntegralインスタンスをサポートします。目に見える速度の違いは、その一般性の代償です。あるプリミティブ型を別のプリミティブ型に切り詰める特定のケースでは、はるかに高速な方法を利用できます。

truncate1そのため、特殊な形式の恩恵を受けているようですが、そうではtruncate2ありません。

なぜtruncate1速いのですか?

GHC.FloatRealFracインスタンスDoubleが定義されている には、次のRULEプラグマがあります

"truncate/Double->Int"              truncate = double2Int

double2Int必要な最適化されたフォームはどこにありますか。これを前述のものと比較してください。明らかに、特に に変換するRULEための同様のプリミティブ操作はありません。DoubleWord16

なぜtruncate2同様に書き換えられないのですか?

GHC User's Guide を引用します。

GHC は現在、ルール LHS を式と一致させるために、非常に単純な構文上の一致アルゴリズムを使用しています。これは、LHS と式が構文的に等しいモジュロ アルファ変換になる置換を探します。必要に応じて、式ではなくパターン (規則) が eta 展開されます。

一致する式は eta 拡張されません。つまり、 に一致するルールは に一致しますが、にforall x. foo xは一致しbar y = foo yませbar = foo

あなたの定義はすべてポイントフリーで書かれているので、RULEfor はDouble -> Int一致しますが、RULEforは一致しDouble -> Word16ません。

于 2013-02-11T22:20:24.853 に答える