2017-03-27 15 views
3

私は(i!= t ++)条件を使用しなければならない問題を解決していました。残念ながら、この状態を使用するとTLEが得られました。しかし、私が(t ++!= i)を使用すると、代わりに正常に提出されました。私は両方の条件がプログラムの下で同じwrtだと思う。私のコンパイラでのプログラムの出力は 3であり、それぞれ第1ループと第2ループで時間がかかる 2つの条件の違いはわかりません。もちろん、私はここにデバッグ(i!= t ++)vs(t ++!= i)

void test() 
{ 
    long b=System.currentTimeMillis(); 
    for(int i=0;i<100001;i++) { 
     int t=0; 
     while (i!=t++) 
     { 
      int x=34; 
      x++; 

     } 
    } 
    System.out.println(System.currentTimeMillis()-b); 

    b=System.currentTimeMillis(); 
    for(int i=0;i<100001;i++) { 
     int t=0; 
     while (t++!=i) 
     { 
      int x=34; 
      x--; 
      x++; 
     } 
    } 
} 
+0

TLEとは何ですか? –

+0

時間制限超過 –

+0

これを読んでくださいhttp://stackoverflow.com/a/5413593/5617860 – Omore

答えて

2

部分的な回答であり、将来の調査が必要です。しかし、当面は答えはです。これはJIT最適化の効果です。また、特にJavaのような動的にコンパイルされた言語では、マイクロベンチマークがパフォーマンステストの最良の選択肢ではないことに注意してください(例:this guru paper参照)。

私は、Windows 10のホーム、java -version版画使用しています:

Javaバージョン "1.8.0_121"
のJava(TM)SEランタイム環境(ビルド1.8.0_121-B13)
は、Java HotSpot(TMを)64ビットサーバーVM(私は離れて最適化されていません、次のようにコードを再構築し、ループを確保するために、外部カウンタとしてxを追加した

)、混合モードを25.121-B13を構築:

void test1() { 
    int x = 0; 
    long b = System.currentTimeMillis(); 
    for (int i = 0; i < 100_001; i++) { 
     int t = 0; 
     while (i != t++) { 
      x++; 
     } 
    } 
    long b1 = System.currentTimeMillis(); 
    System.out.println("T(test1) = " + (b1 - b)); 
    System.out.println("x(test1) = " + x); 
} 

void test2() { 
    int x=0; 
    long b = System.currentTimeMillis(); 
    for (int i = 0; i < 100001; i++) { 
     int t = 0; 
     while (t++ != i) { 
      x++; 
     } 
    } 
    long b1 = System.currentTimeMillis(); 
    System.out.println("T(test2) = " + (b1 - b)); 
    System.out.println("x(test2) = " + x); 
} 

各関数が2回呼び出され:

T(TEST1)= 3745:

t.test1(); 
t.test1(); 
t.test2(); 
t.test2(); 

[OK]を、のは、標準java Test呼び出しの結果を(他のinterpeterの引数が指定されていない)を見てみましょう
x705082704
T(test1)= 0
x(test1)= 705082704
T(TEST2)では、第二の呼び出した後、実行時間を見ることができるように5
X(TEST2)= 705082704
T(TEST2)= 0
X(TEST2)= 705082704

を=どちらの場合も0に等しい。たとえ2番目の呼び出し結果がキャッシュされていないことを保証するためにint x = 0の初期化をint x = new Random().nextInt()に変更しても同じことが起こります。一般に、測定を行う前にJavaインタープリタを「ウォーミングアップ」する必要があります。つまり、同じ実行でコードのパフォーマンスを2回測定し、最初の結果をスローアウェイして、最適化が確実に行われるようにします。しかし、それはオンラインジャッジの演習を解決する際には持っていない贅沢です。

他の部分はここになります。 OracleのJDKには-Xintインタプリタ・スイッチがあり、JITを完全にオフにします。それを使って何が起こるか見てみましょう。私は-XX:+PrintCompilationフラグを使ってコンパイルが行われていないことを確認しました。インタプリタはjava -XX:+PrintCompilation -Xint Testとして呼び出されました。追加の診断)コードがコンパイルされなかったことを意味印刷されていない場合:

T(TEST1)= 56610
X(TEST1)= 705082704
T(TEST1)= 55635
X(TEST1)= 705082704
T(TEST2)= 60247
X(TEST2)= 705082704
T(TEST2)= 58249
X(TEST2)= 705082704

2つの観察:タスクには時間がかかり、結果はすべての呼び出しで似ています。 2つのコードがJITによって異なるように最適化されている理由を調べるためには、より多くの調査が必要です。

EDIT:JIT部分と楽しい2

だから、私は別のコンパイルオプションを試しに行ってきました。一般に、JITが使用するコンパイラには2種類あります。 C1(クライアント)コンパイラは、JVMの起動時間を短縮することを目的としていますが、C2(サーバー)コンパイラほど高速ではありません。私が使用している64ビットJava 8 JVMは、サーバを唯一の使いやすいオプションにしているようです(this FAQを参照してください。ただし、異なるコンパイルレベルは-XX:TieredStopAtLevel=フラグで選択することができます。彼らは、サーバコンパイラのバージョンであることを支持して、test2の最初の呼び出しをより速くする)。

私のマシンには32ビットのJREもあります。これは、サーバーのコンパイラをサポートし、次のバージョン情報与えていません:

Javaバージョン "1.8.0_121"
のJava(TM)SEランタイム環境(ビルドを1.8.0_121-B13)
は、Java HotSpot(TM)クライアントVM(25.121-B13、混在モードの構築)以下のように、このJVMの

結果は次のとおり

T(TEST1)= 3947
X(TEST1)を= 705082704
T(TEST1)= 3985
X(TEST1)= 705082704
T(TEST2)= 4031
X(TEST2)= 705082704
T(TEST2)= 4172
X(TEST2)= 705082704

-1

私の最高の推測を見つけることがバイトコードが生成され、および/または実行されているかの癖だということであることはできませんどこかにバグがあります。

コンピュータプロセッサには、一定の時間に作業している値を格納するために使用できるレジスタの数が限られています。変数が最初に現れるものに基づいて、異なるレジスタに配置されている可能性があります。そして、変数が異なるレジスタに入っていれば、それは他のもののための余地を作るために削除されるものに影響を与えるかもしれません。

値が後で必要になったときにレジスタにない場合、プロセッサはコンピュータのメモリ(またはプロセッサのキャッシュ)から取得する必要があります。これはレジスタに既に存在する場合よりも時間がかかります。

プロセッサが別のステートメントを実行する前に、別のステートメントを実行しようと試みることもあります。しかし、値が変わると中断されることがあります。再度tをロードしようとする直前にt++が発生した場合は、おそらくプロセッサが中断されており、最初から命令を開始する必要があります。 (しかし、私はこれが何が起こっているの主な理由ではないと思うが、それほど大きな効果はないだろう)。

Javaコンパイラは、インスタンスであり、他のインスタンスではありません。

+0

これは無回答です........ –

+0

これは理由だと思いません。ループごとに2つの異なるプログラムを作成すればどうなるでしょうか?また、実行時間も非常に大きな違いをもたらします。そして、私はあなたが4番目のパラ、t、t ++で何を言おうとしているのか分からなかった。私は両方のループがt ++を持っていることを意味します。だからあなたは、問題は並列処理によるものだと言っています –

0

私はコードをテストし、実行時間を確認しました。次の結果(ループ1とループ2のミリ秒単位の時間):

time1 time2 
175.2 171.0 
189.6 187.1 
162.1 164.2 
162.3 162.1 
162.3 166.0 

両方のループが同時に実行されます。ここで

コードを使用すると、文は状況をチャンスだと思う私はなぜわからない

private static void test() 
    { 
    long b; 

    float time1=0; 
    float time2=0; 

    int x=0; 
    for(int l=0;l<10;l++) { 
     b=System.currentTimeMillis(); 
     for(int i=0;i<20001;i++) { 
      int t=0; 
      while (i!=t++) 
      { 
      x++; 
      } 
     } 


     time1+=System.currentTimeMillis()-b; 

     b=System.currentTimeMillis(); 
     x=0; 
     for(int i=0;i<20001;i++) 
      { 
      int t=0; 
      while (t++!=i) 
       { 
        x++; 
       } 


     } 

    time2+=System.currentTimeMillis()-b; 

    } 

    time1/=10; 
    time2/=10 ; 
    System.out.println(time1); 
    System.out.println(time2); 
} 

です。しかし、あなたのプログラムはオンラインコンパイラ(終了時間がある)に時間がなくなったと思います。あなたが議論を変えた後、それが今働いていると思った。 これは、コードがウォームアップしたために、プログラムのランタイムがわずかに短くなることが原因である可能性があります。しかし、これはちょうど推測です....そして、答えとして働くべきではありません。

上記のコードを自分でテストしてください。

質問に答えるには、両方の論理的なエフェクトは同じです。修正後のi ++(値のコピー、現在の値のインクリメント、コピーの生成)と接頭辞++ i(現在の値をインクリメントして結果を返す)には若干の違いがあります。 2番目の操作では操作が1つ少なくなります。しかし、これは異なる計算時間をもたらすべきではない。

このポストを見てくださいWhy is "while (i++ < n) {}" significantly slower than "while (++i < n) {}"なぜyoureのIDEがいくつかの奇妙な結果を与える理由については。

+0

私はあなたのコードを実行し、193.8と0.5の時間を得ました。どのJavaバージョンをお持ちですか? –

+0

@DM https://www.codechef.com/ide –

関連する問題