2012-03-05 3 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 второй раз это 'array_sum ($ samples)/$ sample_count'. поэтому никакого дублирования нет. – Sirko

+0

Возможно [этот] (http://www.php.net/manual/en/function.stats-standard-deviation.php#97369) быстрее? –

ответ

0

Еогеасп по Referance быстрее, чем, у вас уже есть цикл, вы можете вычислить «сумму» в этом цикле. и $ x * $ x так быстрее, чем pow ($ x, 2); Есть некоторые сравнения функций. надеюсь помочь.

Ваша функция микропоры = ~ 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) 

, потому что он не имеет накладных расходов вызова функции.

Тогда вы можете также упростить

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

для предотвращения вызова функции Pow() снова

Чтобы избежать array_sum ($ образцы) вызывается дважды в результате этого изменения, вычислить его один раз и хранить в 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 - я не вижу нигде, что $ samples меняется в вопросе OPs –

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)); 
} 
Смежные вопросы