if-elseステートメントを切り替える利点


168

switchステートメントを使用する場合と、約10のアクションが予想される(現在は同じアクションである)列挙型if30 に対してステートメントを使用する場合のベストプラクティスは何ですかunsigned。パフォーマンスとスペースを考慮する必要がありますが、重要ではありません。スニペットを抽象化したので、命名規則を気にしないでください。

switch ステートメント:

// numError is an error enumeration type, with 0 being the non-error case
// fire_special_event() is a stub method for the shared processing

switch (numError)
{  
  case ERROR_01 :  // intentional fall-through
  case ERROR_07 :  // intentional fall-through
  case ERROR_0A :  // intentional fall-through
  case ERROR_10 :  // intentional fall-through
  case ERROR_15 :  // intentional fall-through
  case ERROR_16 :  // intentional fall-through
  case ERROR_20 :
  {
     fire_special_event();
  }
  break;

  default:
  {
    // error codes that require no additional action
  }
  break;       
}

if ステートメント:

if ((ERROR_01 == numError)  ||
    (ERROR_07 == numError)  ||
    (ERROR_0A == numError)  || 
    (ERROR_10 == numError)  ||
    (ERROR_15 == numError)  ||
    (ERROR_16 == numError)  ||
    (ERROR_20 == numError))
{
  fire_special_event();
}

26
これは「主観的」として編集されますか?本当に?確かに「主観」は、何らかの方法で証明できないもののためのものですか?
アレクサンドラフランクス'18

確かに、それが最も効率的なコードを生成するという点から見ることができますが、最新のコンパイラはどれも同等に効率的であるはずです。結局、これは自転車小屋の色の問題です。
jfs 2008

8
これは主観的ではないと思います。単純なASMの違いが重要です。多くの場合、数秒の最適化を無視することはできません。そして、この質問では、それは宗教戦争や議論ではなく、なぜ速くなるのかについての合理的な説明があります。受け入れられた答えを読んでください。
chakrit 2008


@RichardFranks offtopic:grats!あなたは、私が今まで見たSOのモデレートされた最初の人間です
jungle_mole

回答:


162

スイッチを使用します。

最悪の場合、コンパイラーはif-elseチェーンと同じコードを生成するため、何も失うことはありません。疑わしい場合は、最も一般的なケースを最初にswitchステートメントに入れます。

最良の場合、オプティマイザはコードを生成するより良い方法を見つけるかもしれません。コンパイラーが行う一般的なことは、バイナリー決定ツリーを作成する(平均的なケースでは比較とジャンプを保存する)か、単純にジャンプテーブルを作成する(比較なしで機能する)ことです。


2
技術的には、列挙型の値がジャンプテーブル内にあることを確認するために、比較が1つあります。
0124816 2008

うん。それは本当だ。ただし、列挙型をオンにしてすべてのケースを処理すると、最後の比較が削除される場合があります。
Nils Pipenbrinck 2008

4
一連のifは、理論的にはコンパイラによるスイッチと同じであると分析できますが、なぜその可能性があるのでしょうか。スイッチを使用することで、必要なものを正確に通信できるため、コード生成が容易になります。
jakobengblom2 2008年

5
jakoben:それは可能ですが、スイッチのようなif / elseチェーンに対してのみです。プログラマーがスイッチを使用するため、実際にはこれらは発生しません。私はコンパイラテクノロジーを掘り下げて信頼しました。そのような「役に立たない」構造を見つけるのには、かなりの時間がかかります。コンパイラーの人にとって、そのような最適化は理にかなっています。
Nils Pipenbrinck 08年

5
擬似再帰を構築の容易さと@NilsPipenbrinck if- elseテンプレートメタプログラミングのチェーン、および生成の難しswitch caseチェーンを、そのマッピングはより重要になることがあります。(そして、はい、古代のコメントですが、ウェブは永遠に、または少なくとも次の火曜日までです)
Yakk-Adam Nevraumont

45

例で提供した特殊なケースの場合、最も明確なコードはおそらく次のとおりです。

if (RequiresSpecialEvent(numError))
    fire_special_event();

明らかに、これは問題をコードの別の領域に移動するだけですが、このテストを再利用する機会があります。また、それを解決するためのより多くのオプションがあります。たとえば、std :: setを使用できます。

bool RequiresSpecialEvent(int numError)
{
    return specialSet.find(numError) != specialSet.end();
}

これがオプションであるというだけで、これがRequiresSpecialEventの最良の実装であることを示唆していません。それでも、スイッチやif-elseチェーン、ルックアップテーブル、値のビット操作などを使用できます。決定プロセスが曖昧になるほど、それを分離された関数に含めることから得られる価値が高まります。


5
信用できる。読みやすさは、スイッチとifステートメントの両方よりもはるかに優れています。私は実際にこのようなことを自分で答えるつもりでしたが、あなたは私を倒しました。:-)
mlarsen 2008

列挙値がすべて小さい場合、ハッシュは必要ありません。テーブルのみです。たとえばconst std::bitset<MAXERR> specialerror(initializer); 、と一緒に使用しif (specialerror[numError]) { fire_special_event(); }ます。境界チェックが必要な場合bitset::test(size_t)は、境界外の値で例外をスローします。(bitset::operator[]範囲チェックしません)。 cplusplus.com/reference/bitset/bitset/test。これはおそらく、コンパイラが生成したジャンプテーブルswitch、特にを実装したパフォーマンスよりも優れています。これが単一の分岐しない特別な場合では。
Peter Cordes、2015

@PeterCordesテーブルを独自の関数に入れる方が良いと私はまだ主張しています。私が言ったように、あなたがそれを行うときに開くオプションはたくさんあります、私はそれらすべてを列挙しようとはしませんでした。
Mark Ransom

@MarkRansom:それを抽象化することに反対するつもりはなかった。を使用してサンプル実装を提供したstd::setので、私はそれがおそらく不適切な選択であることを指摘したいと思いました。gccはOPのコードをすでにコンパイルして、32ビットの即時ビットマップをテストしていることがわかります。godbolt:goo.gl/qjjv0e。gcc 5.2は、ifバージョンに対してもこれを行います。また、最近のgcc btでは、1ビットを適切な場所に配置してを使用する代わりに、シフトではなくビットテスト命令を使用しtest reg, imm32ます。
Peter Cordes

この即時定数のビットマップは、ビットマップでのキャッシュミスがないため、大きな利点です。「特別な」エラーコードがすべて64以下の範囲にある場合に機能します。(またはレガシー32ビットコードの場合は32。)ゼロでない場合、コンパイラーは最小のケース値を減算します。要点は、最近のコンパイラーは非常にスマートで、かさばるデータ構造を使用するように指示しない限り、使用するロジックから適切なコードを取得できる可能性があるということです。
Peter Cordes

24

スイッチより高速です。

ループ内で30個の異なる値をif / elseしてみて、switchを使用して同じコードと比較し、switchの速度を確認してください。

ここで、スイッチには1つの実際の問題があります。スイッチは、コンパイル時に各ケース内の値を認識している必要があります。これは次のコードを意味します:

// WON'T COMPILE
extern const int MY_VALUE ;

void doSomething(const int p_iValue)
{
    switch(p_iValue)
    {
       case MY_VALUE : /* do something */ ; break ;
       default : /* do something else */ ; break ;
    }
}

コンパイルされません。

ほとんどの人は定義(Aargh!)を使用し、他の人は同じコンパイル単位で定数変数を宣言して定義します。例えば:

// WILL COMPILE
const int MY_VALUE = 25 ;

void doSomething(const int p_iValue)
{
    switch(p_iValue)
    {
       case MY_VALUE : /* do something */ ; break ;
       default : /* do something else */ ; break ;
    }
}

したがって、最終的には、開発者は「速度+明快さ」と「コード結合」のどちらかを選択する必要があります。

(スイッチを地獄のように混乱させるように書くことはできません...私が現在目にするスイッチのほとんどは、この「混乱する」カテゴリのものです...しかし、これは別の話です...)

2008-09-21を編集:

bk1eは次のコメントを追加しました:「ヘッダーファイルで列挙型として定数を定義することは、これを処理する別の方法です」。

もちろん。

extern型のポイントは、ソースから値を分離することでした。この値をマクロ、単純なconst int宣言、または列挙型として定義すると、値がインライン化されるという副作用があります。したがって、define、enum値、またはconst int値が変更された場合、再コンパイルが必要になります。extern宣言は、値が変更された場合に再コンパイルする必要がないことを意味しますが、その一方で、スイッチを使用できなくなります。結論として、switchを使用すると、switchコードとケースとして使用される変数の間の結合が増加します。OKの場合は、スイッチを使用します。そうでない場合でも、当然のことです。

2013-01-15を編集:

Vlad Lazarenkoが私の回答にコメントし、スイッチによって生成されたアセンブリコードに関する彼の詳細な調査へのリンクを示しました。非常に啓発的:http ://lazarenko.me/switch/


ヘッダーファイルで列挙型として定数を定義することは、これを処理する別の方法です。
bk1e 2008

6
スイッチは常に速い限りませ

1
@Vlad Lazarenko:リンクをありがとう!とても興味深い読み物でした。
paercebal 2013年

1
@AhmedHussein user404725のリンクは無効です。ありがたいことに、私はそれをWayBack Machine:web.archive.org/web/20131111091431/http ://lazarenko.me/2013/01/…で見つけました。実際、WayBack Machineはかなりの恵みになる可能性があります。
ジャックギフィン

おかげで、それは非常に役に立ちます
アーメドフセイン

20

コンパイラはとにかくそれを最適化します-最も読みやすいので、スイッチに行きます。


3
おそらくコンパイラはif-then-elseに触れないでしょう。実際にgccは、それは確実には行われません(そのための正当な理由があります)。Clangは両方のケースをバイナリ検索に最適化します。例えば、参照これを

7

読みやすさだけのためのスイッチ。声明を維持することが難しく、私の意見では読みにくい場合は、巨大です。

ERROR_01://意図的なフォールスルー

または

(ERROR_01 == numError)||

後者はエラーが発生しやすく、最初のものより多くの入力とフォーマットが必要です。


6

読みやすさのためのコード。最適化とコンパイラーはさまざまであり、パフォーマンスの問題が実際のところ問題となることはめったにないため、パフォーマンスの向上を知りたい場合は、プロファイラーを使用します。


6

スイッチを使用してください。それは、それが何のためであり、プログラマーが期待することです。

私は冗長なケースのラベルを入れました-人々を快適にさせるために、私はいつ/どのルールがそれらを除外するのかを思い出そうとしました。
次のプログラマーが言語の詳細について不必要な考えをする必要がないようにしたくありません(数か月後にはあなたかもしれません!)


4

コンパイラーは本当に最適化に優れていswitchます。最近のgccは、の一連の条件を最適化するのにも優れていifます。

godboltでテストケースをいくつか作成しました

case値が近接してグループ化されている場合、gcc、clang、およびiccはすべて、ビットマップを使用して値が特別なものの1つであるかどうかをチェックするのに十分スマートです。

たとえば、gcc 5.2 -O3はswitchto(およびif非常によく似たもの)をコンパイルします。

errhandler_switch(errtype):  # gcc 5.2 -O3
    cmpl    $32, %edi
    ja  .L5
    movabsq $4301325442, %rax   # highest set bit is bit 32 (the 33rd bit)
    btq %rdi, %rax
    jc  .L10
.L5:
    rep ret
.L10:
    jmp fire_special_event()

ビットマップは即時データであるため、データキャッシュへのアクセスミスやジャンプテーブルの可能性がないことに注意してください。

gcc 4.9.2 -O3はswitchをビットマップにコンパイルしますが、1U<<errNumbermov / shiftでを実行します。ifバージョンを一連のブランチにコンパイルします。

errhandler_switch(errtype):  # gcc 4.9.2 -O3
    leal    -1(%rdi), %ecx
    cmpl    $31, %ecx    # cmpl $32, %edi  wouldn't have to wait an extra cycle for lea's output.
              # However, register read ports are limited on pre-SnB Intel
    ja  .L5
    movl    $1, %eax
    salq    %cl, %rax   # with -march=haswell, it will use BMI's shlx to avoid moving the shift count into ecx
    testl   $2150662721, %eax
    jne .L10
.L5:
    rep ret
.L10:
    jmp fire_special_event()

それが1からどのように減算するかに注意してくださいerrNumberleaその操作を移動と組み合わせるために)。これにより、ビットマップを32ビットの即値に適合させることができ、movabsqより多くの命令バイトを必要とする64ビットの即値を回避できます。

より短い(マシンコードで)シーケンスは次のようになります。

    cmpl    $32, %edi
    ja  .L5
    mov     $2150662721, %eax
    dec     %edi   # movabsq and btq is fewer instructions / fewer Intel uops, but this saves several bytes
    bt     %edi, %eax
    jc  fire_special_event
.L5:
    ret

(使用の失敗jc fire_special_eventは遍在的であり、コンパイラのバグです。)

rep ret古いAMD K8およびK10(ブルドーザー以前)のために、分岐ターゲットとそれに続く条件付き分岐で使用されます:「rep ret」とはどういう意味ですか?。それがなければ、分岐予測はこれらの古いCPUではうまく機能しません。

bt(ビットテスト)レジスタ引数を使用すると高速です。1 errNumberビットずつ左シフトしてを実行する作業を組み合わせたものですが、testそれでも1サイクルのレイテンシであり、単一のIntel uopのみです。CISCのセマンティクスがあまりにも遅いため、メモリ引数を使用すると低速になります。「ビット文字列」のメモリオペランドを使用すると、テストするバイトのアドレスは、他の引数(8で除算)に基づいて計算され、メモリオペランドが指す1、2、4、または8バイトのチャンクに限定されません。

Agner霧の命令テーブル、可変数のシフト命令はより遅いbt、最近のIntelの(2つのuopの代わりに、1、およびシフトが必要なのは他のすべてを行いません)。


4

else()の場合のswitch()の利点は次のとおりです。-1. elseに比べてswitchの方がはるかに効率的です。なぜなら、個々のステートメントのtrueまたはfalse条件をチェックする必要がある場合とは異なり、各ケースは前のケースに依存しないためです。

  1. ない場合。単一の式の値の場合、else ifケースの判断は2つの値、つまりtrueまたはfalseのみに基づいているため、switch caseはelse ifより柔軟です。

  2. スイッチの値はユーザー定義ですが、それ以外の場合の値は制約に基づいています。

  3. エラーが発生した場合、switch内のステートメントは簡単にクロスチェックおよび修正できますが、if elseステートメントの場合はチェックが比較的困難です。

  4. スイッチケースははるかにコンパクトで読みやすく、理解しやすいです。


2

IMOこれは、スイッチのフォールスルーが行われた目的の完璧な例です。


C#では、これは秋の思考が起こる唯一のケースです。すぐそこに良い議論があります。
BCS

2

ケースが今後もグループ化されたままになる可能性がある場合(複数のケースが1つの結果に対応する場合)は、スイッチの方が読みやすく、保守が容易であることがわかる場合があります。


2

彼らは同様にうまく機能します。最新のコンパイラーを与えられた場合、パフォーマンスはほぼ同じです。

ifステートメントは、読みやすく、柔軟性があるため、caseステートメントよりもifステートメントを優先します。 "|| max <min"のように、数値の等価性に基づいていない他の条件を追加できます。ただし、ここに投稿した単純なケースの場合、それは実際には問題ではなく、最も読みやすい方法で実行してください。


2

スイッチを使用することをお勧めします。長いif条件を読み取るよりも、スイッチのケースのリストを見て、何をしているのかを確認する方が簡単です。

状態の重複ifは目に難しいです。の1つ==が書かれているとしましょう!=。気づきますか?または、「numError」の1つのインスタンスが「nmuError」と書かれていて、たまたまコンパイルされただけなのですか?

私は通常、スイッチの代わりにポリモーフィズムを使用することを好みますが、コンテキストの詳細がなければ、言うのは難しいです。

パフォーマンスについては、プロファイラーを使用して、実際の状況と同様の条件でアプリケーションのパフォーマンスを測定するのが最善の策です。そうでなければ、おそらく間違った場所で、間違った方法で最適化しています。


2

私はスイッチソリューションの柔軟性に同意しますが、IMOはここでスイッチをハイジャックしています。
スイッチの目的は、値に応じて異なる処理を行うことです。
あなたは擬似コードであなたのアルゴを説明しなければならないとしたら理由場合は、使用したい、意味的に、それはそれが何であるかです:whatever_errorこれを行う場合は ...
だから、あなたは、各エラーの固有のコードを持っているようにコードを変更するにはいつかを意図していない限り、 私は使うだろうなら


2
フォールスルー事件に同意しないのと同じ理由で、私は同意しません。私はスイッチを「01、07、0A、10、15、16、および20が特別なイベントを発火した場合」と読みました。別のセクションへのフォールスルーはありません。これは、C ++構文のアーティファクトであり、各値に対して 'case'キーワードを繰り返します。
MSalters 2008

1

明快さと慣習のためにif文を選択しますが、一部は異論があると思います。結局のところ、あなたはif何らかの条件が真である何かをしたいのです!1つのアクションでスイッチを使用することは、少し不必要に思えます。


1

SWITCHを使用します。この方法では、異なる結果を実装するだけで済みます。10個の同一のケースでデフォルトを使用できます。必要な変更が明示的にその変更を実装するだけの場合、デフォルトを編集する必要はありません。IFとELSEIFを編集するよりも、SWITCHにケースを追加または削除する方がはるかに簡単です。

switch(numerror){
    ERROR_20 : { fire_special_event(); } break;
    default : { null; } break;
}

たぶん、可能性のリストに対して配列(この場合はnumerror)をテストすることもできます。配列を使用すると、結果が確実にない限り、SWITCHは使用されません。


合計約30のエラーがあります。10には特別なアクションが必要なので、アクションを必要としない〜20エラーのデフォルトを使用しています...
Zing-

1

エラーコードは30個しかないので、独自のジャンプテーブルをコード化し、コンパイラーが正しいことをするのではなく、自分ですべての最適化を選択します(ジャンプが常に最も速くなります)。また、コードが非常に小さくなります(ジャンプテーブルの静的宣言を除く)。また、デバッガーを使用すると、必要に応じて、テーブルデータを直接ポークするだけで、実行時に動作を変更できるという副次的な利点もあります。


うわー、それは単純な問題を複雑な問題に変える方法のように思えます。コンパイラーがあなたのために素晴らしい仕事をするとき、なぜすべてのその問題に行きなさい。さらに、それは明らかにエラーハンドラーであるため、速度がそれほど重要になることはあまりありません。スイッチは、読み取りと保守がはるかに簡単です。
MrZebra 2008

テーブルはほとんど複雑ではありません-実際、コードへの切り替えよりもおそらく簡単です。そして声明はパフォーマンスが要因であると述べました。
グレッグホイットフィールド、

それは時期尚早の最適化のように聞こえます。enum値を小さく連続したままにしておく限り、コンパイラーがそれを実行します。別の関数にスイッチを配置すると、Mark Ransomが彼の答えで示唆しているように、それを使用するコードを簡潔に保ち、同じ小さなコードの利点を提供します。
Peter Cordes、2015

また、自分で何かを実装する場合は、を作成しstd::bitset<MAXERR> specialerror;、次にを作成しif (specialerror[err]) { special_handler(); }ます。これは特にジャンプテーブルよりも高速になります。取られない場合。
Peter Cordes

1

ベストプラクティスについてはわかりませんが、スイッチを使用し、「デフォルト」を介して意図的なフォールスルーをトラップします


1

審美的に私はこのアプローチを支持する傾向があります。

unsigned int special_events[] = {
    ERROR_01,
    ERROR_07,
    ERROR_0A,
    ERROR_10,
    ERROR_15,
    ERROR_16,
    ERROR_20
 };
 int special_events_length = sizeof (special_events) / sizeof (unsigned int);

 void process_event(unsigned int numError) {
     for (int i = 0; i < special_events_length; i++) {
         if (numError == special_events[i]) {
             fire_special_event();
             break;
          }
     }
  }

データをもう少しスマートにして、ロジックを少し控えめにします。

奇妙に見えます。これがインスピレーションです(私がPythonでそれを行う方法から):

special_events = [
    ERROR_01,
    ERROR_07,
    ERROR_0A,
    ERROR_10,
    ERROR_15,
    ERROR_16,
    ERROR_20,
    ]
def process_event(numError):
    if numError in special_events:
         fire_special_event()

4
言語の構文、ソリューションの実装方法に影響を与えます... => Cでは醜く、Pythonでは見栄えがします。:)
rlerallut

ビットマップを使用しますか?error_0aが0x0aなどの場合、それらをlong longのビットとして配置できます。long long special_events = 1LL << 1 | 1LL << 7 | 1LL <<は0xaは...そして、使用している場合(special_events&(1LL << numError)fire_special_event()
paperhorse

1
ああ。あなたは(Nは例取り扱わの数である)O(N)最悪の場合にO(1)(ジャンプテーブルが生成されている場合)最悪の場合の操作になってきた、あなたは使用break外をcase(はい、マイナー罪ですが、それでも罪です)。:)
Mac

うん?彼はパフォーマンスとスペースは重要ではないと述べました。私は単に問題の別の見方を提案していました。人間があまり考えない方法で問題を表すことができれば、コンピュータがもっと考えなければならないことを意味するかどうか、私は通常気にしません。
mbac32768

1
while (true) != while (loop)

おそらく、最初のループはコンパイラーによって最適化されているため、ループ数を増やすと2番目のループが遅くなるのはこのためです。


これはMcAnixの回答に対するコメントのようです。それは唯一のタイミングで、その試みの問題点の一つだifswitchJavaでループ終了条件として。
Peter Cordes、2015

1

プログラムのコンパイルに関しては、違いがあるかどうかわかりません。しかし、プログラム自体とコードをできるだけ単純に保つことに関しては、私は個人的にはあなたが何をしたいかに依存していると思います。if else if elseステートメントには利点があると私は思います:

関数(標準ライブラリまたはパーソナル)を条件として使用できる特定の範囲に対して変数をテストできます。

(例:

`int a;
 cout<<"enter value:\n";
 cin>>a;

 if( a > 0 && a < 5)
   {
     cout<<"a is between 0, 5\n";

   }else if(a > 5 && a < 10)

     cout<<"a is between 5,10\n";

   }else{

       "a is not an integer, or is not in range 0,10\n";

ただし、if else if elseのステートメントは、急いで(最善の試みにもかかわらず)複雑で厄介なものになる可能性があります。switchステートメントは、より明確でわかりやすく、読みやすい傾向があります。ただし、特定の値に対してテストする場合にのみ使用できます(例:

`int a;
 cout<<"enter value:\n";
 cin>>a;

 switch(a)
 {
    case 0:
    case 1:
    case 2: 
    case 3:
    case 4:
    case 5:
        cout<<"a is between 0,5 and equals: "<<a<<"\n";
        break;
    //other case statements
    default:
        cout<<"a is not between the range or is not a good value\n"
        break;

if-else if-elseステートメントの方が好きですが、それはあなた次第です。関数を条件として使用したい場合、または範囲、配列、またはベクトルに対して何かをテストしたい場合、および/または複雑な入れ子に対処することを気にしない場合は、If else if else elseを使用することをお勧めします。単一の値に対してテストする場合、またはクリーンで読みやすいブロックが必要な場合は、switch()ケースブロックを使用することをお勧めします。


0

私は速度とメモリ使用量についてあなたに話す人ではありませんが、switchステートメントを見ると、大きなifステートメント(特に2〜3か月後)を理解するよりもはるかに理解しやすくなります。


0

古いことは知っていますが

public class SwitchTest {
static final int max = 100000;

public static void main(String[] args) {

int counter1 = 0;
long start1 = 0l;
long total1 = 0l;

int counter2 = 0;
long start2 = 0l;
long total2 = 0l;
boolean loop = true;

start1 = System.currentTimeMillis();
while (true) {
  if (counter1 == max) {
    break;
  } else {
    counter1++;
  }
}
total1 = System.currentTimeMillis() - start1;

start2 = System.currentTimeMillis();
while (loop) {
  switch (counter2) {
    case max:
      loop = false;
      break;
    default:
      counter2++;
  }
}
total2 = System.currentTimeMillis() - start2;

System.out.println("While if/else: " + total1 + "ms");
System.out.println("Switch: " + total2 + "ms");
System.out.println("Max Loops: " + max);

System.exit(0);
}
}

ループカウントを変更すると、大きく変化します。

一方、if / else:5msスイッチ:1ms最大ループ:100000

while if / else:5ms Switch:3ms Max Loops:1000000

while if / else:5ms Switch:14ms Max Loops:10000000

while if / else:5ms Switch:149ms Max Loops:100000000

(必要に応じてステートメントを追加します)


3
良い点ですが、申し訳ありませんが、あなたは間違った言語です。言語を変えると、大きく変わります;)
ガブリエルシュライバー2010

2
if(max) breakループは関係なく、ループ回数の一定の時間で実行されますか?JITコンパイラのように聞こえるのは、ループをに最適化するのに十分スマートですcounter2=max。また、最初の呼び出しのcurrentTimeMillisオーバーヘッドが大きい場合は、スイッチよりも遅くなるかもしれません。すべてがまだJITコンパイルされていないからですか?ループを別の順序で配置すると、おそらく異なる結果が得られます。
Peter Cordes
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.