最速の方法は、各桁を抽出して追加することです。
public static void main(String... args) {
// check values
int runs = 1000000;
for (int i = 100; i < runs; i++) {
int sum = sumDigits(i - 1);
int sum1 = sumDigits(i);
int sum2 = sumDigits(sum, i);
if (sum1 != sum2) throw new AssertionError(i + ": " + sum1 + " != " + sum2);
}
long start = System.nanoTime();
for (int i = 0; i < runs; i++) {
int sum = sumDigits(i);
// prevent optimising away.
if (sum < 0) throw new AssertionError();
}
long time = System.nanoTime() - start;
System.out.printf("sumDigits took an average of %,d ns%n", time / runs);
long start2 = System.nanoTime();
int lastSum = 0;
for (int i = 0; i < runs; i++) {
int sum = sumDigits(lastSum, i);
lastSum = sum;
// prevent optimising away.
if (sum < 0) throw new AssertionError();
}
long time2 = System.nanoTime() - start2;
System.out.printf("sumDigits using previous value took an average of %,d ns%n", time2 / runs);
long large = Long.MAX_VALUE - runs - 1;
long start3 = System.nanoTime();
for (int i = 0; i < runs; i++) {
int sum = sumDigits(large + i);
// prevent optimising away.
if (sum < 0) throw new AssertionError();
}
long time3 = System.nanoTime() - start3;
System.out.printf("sumDigits took an average of %,d ns%n", time3 / runs);
long start4 = System.nanoTime();
int lastSum2 = sumDigits(large);
for (int i = 0; i < runs; i++) {
int sum = sumDigits(lastSum2, large + i);
lastSum2 = sum;
// prevent optimising away.
if (sum < 0) throw new AssertionError();
}
long time4 = System.nanoTime() - start4;
System.out.printf("sumDigits using previous value took an average of %,d ns%n", time4 / runs);
}
public static int sumDigits(long n) {
int sum = 0;
do {
sum += n % 10;
n /= 10;
} while (n > 0);
return sum;
}
public static int sumDigits(int prevSum, long n) {
while (n > 0 && n % 10 == 0) {
prevSum -= 9;
n /= 10;
}
return prevSum + 1;
}
版画
sumDigits took an average of 32 ns
sumDigits using previous value took an average of 10 ns
sumDigits took an average of 79 ns
sumDigits using previous value took an average of 7 ns
大きな値の場合、約 70 ns を節約できます。コードに多少の複雑さが加わります。1 から 10^18 までずっと数えることはできないため、最初の sumDigit を使用して合計をブートストラップする必要があります。