2017-12-25 2 views
2

私は1000を1kと言う小さな関数を持っています。PHPループはどれくらい悪いですか

<?php 

/** 
* /Converts a number into a short version, eg: 1000 -1k. 
* 
* @param int $number The number 
* @param int $precision The precision 
* 
* @return string The formated number 
*/ 
function short_number_format($number, $precision = 1) 
{ 
    $lookup = [ 
     1 => '', 
     1000 => 'K', 
     1000000 => 'M', 
     1000000000 => 'B', 
     1000000000000 => 'T', 
    ]; 
    $result = ''; 
    foreach ($lookup as $boundary => $postfix) { 
     if ($number < 900 * $boundary) { 
      $result = number_format($number/$boundary, $precision).$postfix; 
      break; 
     } 
    } 
    //if we didnt get the result which is most likely to happen 
    // for larger numbers (rarely) , return the plain number 

    return $result ?: number_format($number, $precision); 
} 

シニアの開発者の中には、ループのためにコードがひどく遅くなってしまったと言われました。 それは本当ですか?

+0

これは5つの要素の単なる配列です –

+0

コードに問題があったとしても、アルゴリズムの複雑さに起因する可能性があります。ループ自体のためではありません。 – Carcigenicate

+0

コードは非常にうまく動作します。ただ、ループが遅くなるというデベロッパーの主張 –

答えて

0

このコードについては何も表示されません。パフォーマンスに関する懸念。固定長ループはO(1)演算であり、いくつかの基本的な計算は性能問題の根本原因ではありません。

私はギガバイトのためにあなたのポストフィックスの誤植を修正し、実行時にパフォーマンスの問題が実際に見られたためにあなたの懸念があるかどうかを確認するためにdevに相談します。たぶん、あなたはいくつかのタイマーを入れて、どのような操作が最も時間を費やしているかを測定することができます。また、単体テストを作成して、自分の関数のパフォーマンスについて直感的に知っていることを確認することもできます。

追加:ループを使用しない文字列ベースのバージョンを作成し、使用しているバージョンに対してタイムアウトしました。 no-loopバージョンは非常にわずかに速く実行されるかもしれませんが、あなたは既存のバージョンがかなり適度なCPU上で何十万もの要求をすでに処理できることがわかります。あなたの関数のミクロ最適化は、目に見える影響を与えることはまずありません。

<!DOCTYPE html> 
<html> 
<body> 
<?php 
$t1 = microtime(true); 
for ($i=0; $i<100000; $i++) { 
    scaleV1($i, $i%3 + 1); 
} 
timesince($t1); 
$t2 = microtime(true); 
for ($i=0; $i<100000; $i++) { 
    short_number_format($i, $i%3 + 1); 
} 
timesince($t2); 


function timesince($micro) { 
    $sec=(microtime(true) - $micro); 
    echo "<p>" . number_format($sec, 3) . "</p>\n"; 
} 


function scaleV1($number, $precision=1) { 
    $scale_id=" KMGTP"; 
    $w=strlen(intval($number)); 
    $scale=intval($w/3); 
    if (($w%3==0) && (substr($number,0,1)!=9)) $scale--; 
    $postfix=$scale==0 ? '' : $scale_id[$scale]; 
    return number_format(($number/pow(1000,$scale)), $precision) . 
$postfix; 
} 

function short_number_format($number, $precision = 1) 
{ 
    $lookup = [ 
     1 => '', 
     1000 => 'K', 
     1000000 => 'M', 
     1000000000 => 'G', 
     1000000000000 => 'T', 
    ]; 
    $result = ''; 
    foreach ($lookup as $boundary => $postfix) { 
     if ($number < 900 * $boundary) { 
      $result = number_format($number/$boundary, 
$precision).$postfix; 
      break; 
     } 
    } 
    return $result ?: number_format($number, $precision); 
} 
?> 

</body> 
</html> 
+0

これは計算されたバイトであるという前提が正しくない可能性があります。私の前提は、これらのポストフィックスの値が単に数千、数百万、数十億などを表しているということです。あなたが好きな場合は入力番号をポーカーチップまたはSO repポイントと考えることができます。 – mickmackusa

+0

はい、私はあなたが正しいと思います。 – phatfingers

3

これを試してみてください:

$lookup = [ 
    900 => '', 
    900000 => 'K', 
    900000000 => 'M', 
    900000000000 => 'B', 
    900000000000000 => 'T', 
]; 

$result = ''; 
foreach ($lookup as $boundary => $postfix) { 
    if ($number < $boundary) { 
     $result = number_format($number/($boundary/900), $precision) . $postfix; 
     break; 
    } 
} 

この方法であなたの代わりに乗算たびのdivison ONE時間を行います。

  • 編集:改善された答え:

部門は乗算よりも多くの処理を要したので、私たちはより良いにそれを変更:より速く、かなり速い

$result = number_format(($number*900) /$boundary, $precision) . $postfix; 

これは理論的にすべきか、あなたのshort_number_format( )関数が反復回数の多い別のループから呼び出される

+0

"部門は掛け算よりも処理コストが高いため、いくつかの証拠が必要です。 – zerkms

+0

これを参照してください:https://stackoverflow.com/a/17371315/6281135 –

+0

これはちょうど常識です!あなたが掛け合わせるときには、あなただけを追加するだけですが、あなたが分けるときには、確認して対処するためのリマインダの確率で減算します。 –

0

これは、ループや分岐せずに別の方法です:私たちは、ルックアップ列にインデックスとしての桁数を使用し、この方法では

function short_number_format($number, $precision = 1) 
{ 
    $lookup = [ 
       1 => [1,''], 
       2 => [1,''], 
       3 => [1,''] 
       4 => [1000,'K'], 
       5 => [1000,'K'], 
       6 => [1000,'K'], 
       7 => [1000000,'M'], 
       8 => [1000000,'M'], 
       9 => [1000000,'M'], 
       10 => [1000000000,'B'], 
       11 => [1000000000,'B'], 
       12 => [1000000000,'B'], 
       13 => [1000000000000,'T'], 
       14 => [1000000000000,'T'], 
       15 => [1000000000000,'T'] 
     ]; 

     $N = floor(log($number, 10) + 1); 
     $result=$number/$lookup[$N][0]; 
return number_format ($result,$precision) . $lookup[$N][1]; 
} 

と除数と手紙を取得するには、0と1を使用しますそれぞれ、

$N = strpos(strval($number),".")-1; // only if $number has dot like a double 

-EDIT入力番号を仮定文字列関数の代わりに数学を使用して、別の方法(ドットとの二重されていない。

別の方法は、($番号は二重である場合にのみドットを含むフロート)を使用することですテスト): :

function short_number_format($number, 
$precision = 1) 
{ 
$lookup = [ 
      1 => [0,''], 
      2 => [0,''], 
      3 => [0,''] 
      4 => [3,'K'], 
      5 => [3,'K'], 
      6 => [3,'K'], 
      7 => [6,'M'], 
      8 => [6,'M'], 
      9 => [6,'M'], 
      10 => [9,'B'], 
      11 => [9,'B'], 
      12 => [9,'B'], 
      13 => [12,'T'], 
      14 => [12,'T'], 
      15 => [12,'T'] 
    ]; 
$sn = strval($number); 
$N = strpos($sn,".") - 1; 
$pos = $N - $lookup[$N][0]; 
$sn = str_replace('.', '', $sn) ; 
$sn = substr_replace($sn, ".", $pos, 0); 
return number_format (doubleval($sn),$precision) . $lookup[$N][1]; 


} 
  • 以上20K upvotesで答えを読んだ後、非分岐の引数を追加しました、それはその述べ

    親指の一般的なルールは、データ依存クリティカルなループに分岐避けるためです

    参照:https://stackoverflow.com/a/11227902/6281135

    も同じスレッドからそれがソートされたデータを使用して、IFを維持したい場合は高速に実行されているようです文章。データとは、別のループから呼び出す場合に備えて、関数に渡されるデータを意味します。

+0

多次元配列は、理解していれば美しく高速です。 –

+0

アイデアは、より少ないリソースを消費する(時間がかかりません)1つの答えが付いてくることです。 –

+0

私はOPは数兆にしかカバーしたくないと思う –

関連する問題