2016-09-06 5 views
5

jmhで遊んでいる間、私は奇妙なことを見つけました。私は説明できません。なぜ(n mod const)が(const mod n)より速いのですか?

@BenchmarkMode(Mode.SingleShotTime) 
@Measurement(iterations = 10, batchSize = Integer.MAX_VALUE) 
@Warmup(iterations = 5, batchSize = Integer.MAX_VALUE) 
@State(Scope.Thread) 
public class Tests { 
    private int value; 

    @Setup(Level.Iteration) 
    public void setUp() { 
     value = 1230; 
    } 

    @Benchmark 
    public boolean testConstModN() { 
     return 12345 % value == 0; 
    } 

    @Benchmark 
    public boolean testNModConst() { 
     return value % 12345 == 0; 
    } 
} 

結果は

Benchmark     Mode Cnt Score Error Units 
Tests.testConstModN   ss 10 10.789 ± 0.305 s/op 
Tests.testNModConst   ss 10 7.550 ± 0.067 s/op 

私はJDK 1.8.0_101、VM 25.101-B13、インテル(R)Core(TM)i7-4770 CPUする@ 3.40GHz(ファミリ上で実行しています以下であります: 0x6、モデル:0x3c、ステッピング:0x3)

constに等しい値を設定するか、値を0xffffffffに設定しても何も変わりません。

+0

等価であるのにCONST%を実行してみてください。 – Erik

+0

'value'を12345に設定し、1230を定数として使うとどうなりますか? – GriffeyDog

+0

質問に追加情報を追加しました。 'const'と' value'の値が何であるかは関係ありません。 – Slonopotamus

答えて

7

に整数の相対的なサイズに依存CPUのDIVMOD命令は50サイクル以上の原価計算、非常に高価です。可変除数を使用する場合、これらの指示を使用することは避けられません。ただし、定数除数を使用する場合は、MULADDSHRなど、より安価な命令の短いシーケンスにコンパイルすることができます。

Hacker's delight, chapter 10は、この問題を解決するいくつかのアルゴリズムをカバーしています。

+0

具体的には、次のような強度の低下が考えられます。https://gmplib.org/~tege/divcnst-pldi94pdf –

+0

モジュラー乗法逆数(大きなマジック定数を乗算して上半分を使用する) –

+0

これは、JITコンパイラーから出された実際のマシンコードを検査することで解決できます。私は一度それをしました、多分私はその答えを見つけることができます... –

1

弾性率は内部でのみに必要となる、1230年には12345未満である

testNModConst()ではそれだけで直感

それが原因%オペレータの性質のだだこの回答を注意してください彼らのサイズを確認していることを実感12345

testConstModN() 12345が1230より大きいため、モジュラスは答えを計算するために一連の操作(減算)を行う必要があります。

それは一定の

+0

良い説明。ネイティブのCまたはアセンブリ環境で結果を確認するのは興味深いでしょう。 – Beethoven

+1

良い推測です。残念ながら、nとconstの値には依存しません。 – Slonopotamus

+2

この回答は、モジュロ演算がどのようにハードウェアレベルで実行されるかを反映していません。 –

関連する問題