あなたのアルゴリズムはうまく見えます。 StringBuffer
はスレッドセーフであるため、への呼び出しごとにロックを取得するため、非常に低速ですappend
。を使用StringBuilder
し、必要になることがわかっている容量で構築しますk
。StringBuilder
これにより、増大する文字列に 対応するために内部のバッファが拡張されるときに、データの複数のコピーが防止されます。
StringBuffer
ドキュメントを読むと、これは明らかです。
リリースJDK5の時点で、このクラスには、単一スレッドStringBuilderで使用するために設計された同等のクラスが追加されています。StringBuilderクラスは、同じ操作をすべてサポートするため、通常はこれよりも優先して使用する必要がありますが、同期を実行しないため、より高速です。
出力の正確なサイズを事前に知っているので、バイトの配列を使用して数字を保持することもできます。それでも、長さ10^6の文字列への最終的な変換と出力にはコストがかかります。以下のコードを実行すると、バイト配列の作成に0.016秒、文字列への変換に0.06秒、印刷に1秒以上かかります。進歩するには、Javaで高速I/Oを実行する方法について調査する必要があります。Cまたはハードウェアに近い別の言語に切り替える場合、通常のI/Oルーチンは十分に高速である可能性があります。
public void run() {
int k = 1000000;
long start = System.currentTimeMillis();
int tot = 4687;
int divisor = 33102;
byte [] buf = new byte[k];
int tmp = tot;
for (int i = 0; i < k; i++) {
tmp = tmp * 10;
int res = tmp / divisor;
buf[i] = (byte)(res + '0');
tmp = tmp - res * divisor;
}
System.out.println((System.currentTimeMillis() - start) * .001);
String s = new String(buf);
System.out.println((System.currentTimeMillis() - start) * .001);
System.out.print("3."); System.out.println(s);
System.out.println((System.currentTimeMillis() - start) * .001);
}