2012-03-05 88 views
-1

我有一個腳本調用該函數超過10萬次,所以我找反正擠多一點表現出來。優化該功能

您能否提供最佳化或在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'兩次。 – 2012-03-05 13:26:17

+0

@OliCharlesworth第二次是'array_sum($ samples)/ $ sample_count'。所以沒有重複。 – Sirko 2012-03-05 13:29:38

+0

也許[這一個](http://www.php.net/manual/en/function.stats-standard-deviation.php#97369)更快? – 2012-03-05 13:35:09

回答

0

foreach by referance比for更快,你已經有一個循環,你可以在這個循環中計算「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()的最快速的 – 2012-03-05 14:03:54

+0

我們已經計算出版本2是最快的,但在返回中,您仍然擁有pow(),這會不會更快地將調用替換爲pow在回報線?我的測試說不,但差異很小 - 想法? – 2012-03-11 16:38:34

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

將是快於

pow($samples[$current_sample], 2) 

,因爲它不具備的功能調用的開銷。

那麼你也可以簡化

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

防止調用戰俘()函數再次

爲了避免array_sum($樣本)被調用兩次作爲變化的結果,一旦計算出它與在循環之前存儲到var,然後在公式中引用該var。

編輯

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 2012-03-05 13:37:59

+0

@Vytautas - 我看不到任何$樣本在OP中改變的任何問題 – 2012-03-05 13:56:20

0

通過計算自己相應的值替換兩個呼叫到array_sum。這樣,你只需要一次而不是三次遍歷陣列。

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)); 
}