Java 8 ストリームを練習するために、次のネストされたループを Java 8 ストリーム API に変換してみました。a^b (a,b < 100) の最大桁合計を計算し、Core i5 760 で ~0.135 秒かかります。
public static int digitSum(BigInteger x)
{
int sum = 0;
for(char c: x.toString().toCharArray()) {sum+=Integer.valueOf(c+"");}
return sum;
}
@Test public void solve()
{
int max = 0;
for(int i=1;i<100;i++)
for(int j=1;j<100;j++)
max = Math.max(max,digitSum(BigInteger.valueOf(i).pow(j)));
System.out.println(max);
}
私の解決策は、並列処理のために高速になると予想していましたが、実際には 0.25 秒かかりました ( parallel()
.
int max = IntStream.range(1,100).parallel()
.map(i -> IntStream.range(1, 100)
.map(j->digitSum(BigInteger.valueOf(i).pow(j)))
.max().getAsInt()).max().getAsInt();
私の質問
- 変換を正しく行いましたか、またはネストされたループをストリーム計算に変換するより良い方法はありますか?
- ストリーム バリアントが古いものよりもずっと遅いのはなぜですか?
- parallel() ステートメントが実際に時間を 0.19 秒から 0.25 秒に増やしたのはなぜですか?
マイクロベンチマークは壊れやすく、並列処理は大きな問題の場合にのみ価値があることを知っていますが、CPU の場合、0.1 秒でも永遠ですよね?
アップデート
Eclipse Kepler の Junit 4 フレームワークで測定します (テストの実行にかかった時間を示します)。
100 ではなく a,b<1000 の結果:
- 伝統的なループ 186s
- 順次ストリーム 193s
- パラレル ストリーム 55s
更新 2sum+=Integer.valueOf(c+"");
(Peter に感謝します!)
に置き換えるsum+= c - '0';
ことで、並列メソッドの 10 秒が短縮され、45 秒になりました。こんなに大きなパフォーマンスへの影響を期待していませんでした!
また、並列処理を CPU コアの数 (私の場合は 4) に減らしても、時間が 44.8 秒にしか短縮されなかったため、あまり効果がありませんでした (はい、a と b=0 を追加しますが、これはパフォーマンスの多く):
int max = IntStream.range(0, 3).parallel().
.map(m -> IntStream.range(0,250)
.map(i -> IntStream.range(1, 1000)
.map(j->.digitSum(BigInteger.valueOf(250*m+i).pow(j)))
.max().getAsInt()).max().getAsInt()).max().getAsInt();