2012-03-05 13 views
-1

私はこの関数を100k回以上呼び出すスクリプトを用意していますので、とにかくそれより少しパフォーマンスを絞りたいと思っています。この関数を最適化する

PHPで標準偏差を計算するための最適化または別の方法を提案できますか?

function calcStandardDev($samples){ 


    $sample_count = count($samples); 

    for ($current_sample = 0; $sample_count > $current_sample; ++$current_sample) $sample_square[$current_sample] = pow($samples[$current_sample], 2); 

    return sqrt(array_sum($sample_square)/$sample_count - pow((array_sum($samples)/$sample_count), 2)); 

} 
+1

あなたが計算されている 'array_sum($ sample_square)/ $ sample_count'二回。 –

+0

@OliCharlesworth 2回目は 'array_sum($ samples)/ $ sample_count'です。重複はありません。 – Sirko

+0

おそらく[this one](http://www.php.net/manual/en/function.stats-standard-deviation.php#97369)は高速ですか? –

答えて

0

foreachが参照よりも速いため、すでにループがある場合は、このループで "sum"を計算できます。 $ x * $ xはpow($ x、2)よりも速いです。 いくつかの機能の比較があります。助けて欲しい。

あなたの機能のmicrotime =〜0.526

第二の機能 =〜0.290

<?php 
    function calcStandardDev($samples) 
    { 


     $sample_count = count($samples); 

     for ($current_sample = 0; $sample_count > $current_sample; ++$current_sample) 
      $sample_square[$current_sample] = pow($samples[$current_sample], 2); 

     return sqrt(array_sum($sample_square)/$sample_count - pow((array_sum($samples)/$sample_count), 2)); 

    } 

    function calcStandardDev2($samples) 
    { 
     $sample_count = count($samples); 

     $sum_sample_square = 0; 
     $sum_sample   = 0; 

     foreach ($samples as &$sample) 
     { 
      $sum_sample   += $sample; 
      $sum_sample_square += $sample * $sample; 
     } 

     return sqrt($sum_sample_square/$sample_count - pow($sum_sample/$sample_count,2)); 

    } 

    function calcStandardDev3($samples) 
    { 
     $sample_count = count($samples); 

     $sum_sample_square = 0; 
     $sum_sample   = 0; 

     foreach ($samples as &$sample) 
     { 
      $sum_sample   += $sample; 
      $sum_sample_square += pow($sample ,2); 
     } 

     return sqrt($sum_sample_square/$sample_count - pow($sum_sample/$sample_count,2)); 

    } 

    echo "<pre>"; 
    $samples = range(2,100000); 

    $start = microtime(true); 
    echo calcStandardDev($samples)."\r\n"; 
    $end = microtime(true); 
    echo $end - $start ."\r\n"; 
    echo "-------\r\n"; 

    $start = microtime(true); 
    echo calcStandardDev2($samples)."\r\n"; 
    $end = microtime(true); 
    echo $end - $start."\r\n"; 
    echo "-------\r\n"; 

    $start = microtime(true); 
    echo calcStandardDev3($samples)."\r\n"; 
    $end = microtime(true); 
    echo $end - $start; 
    echo "-------\r\n"; 
?> 
+0

ありがとう!すべてのソリューションの中でcalcStandardDev2()として投稿されたものが最も速いです –

+0

バージョン2は既に早いですが、返されてもまだpow()を持っていますが、これはpowリターンラインで?私のテストはいいえと言いますが、違いはごくわずかです - 考え? –

1
$samples[$current_sample] * $samples[$current_sample] 

それは、関数呼び出しのオーバーヘッドを持っていないため

pow($samples[$current_sample], 2) 

よりも高速になるだろう。

その後も、その倍の変化の結果として呼び出されているarray_sum($サンプル)を回避するために、再び

をPOW()関数を呼び出す防ぐために

pow((array_sum($samples)/$sample_count), 2)); 

を簡素化することができます一度それを計算し、ループの前にvarに格納してから、varを式で参照するだけです。

EDIT

function calcStandardDev($samples){ 
    $sample_count = count($samples); 
    $sumSamples = array_sum($samples); 

    for ($current_sample = 0; $sample_count > $current_sample; ++$current_sample) 
     $sample_square[$current_sample] = $samples[$current_sample] * $samples[$current_sample]; 


    return sqrt(array_sum($sample_square)/$sample_count - (($sumSamples/$sample_count) * 
                   ($sumSamples/$sample_count) 
                  ) 
       ); 

} 
+0

私は '$ samples'が各ループ呼び出しで同じではないと考えています – Vytautas

+0

@Vytautas - OPの質問で$ samplesが変化しているところはどこにも見えません –

0

それぞれの値を自分で計算することにより、array_sumへの呼び出しの両方を交換してください。そうすれば、3回ではなく1回だけあなたのアレイを歩くことができます。

function calcStandardDev($samples){ 

    $sample_count = count($samples); 
    $sum = 0; 
    $sum_sqaure = 0; 

    for ($current_sample = 0; $sample_count > $current_sample; ++$current_sample) { 
     $sum_square += pow($samples[$current_sample], 2); 
     $sum += $samples[$current_sample]; 
    } 

    return sqrt($sum_square/$sample_count - pow($sum/$sample_count, 2)); 
}