3 回答

TA貢獻(xiàn)1827條經(jīng)驗 獲得超4個贊
請注意,使用BigInteger意味著數(shù)字以及兩個數(shù)字之間的差異可能會很大。從字面上看,從下邊界到上邊界循環(huán)可能需要很長時間。相反,您可以使用封閉形式的變體sum(1..N) = (N*(N+1))/2。1使用它對 from toupper和 from 1to 的數(shù)字求和lower,然后將兩者結(jié)合起來以獲得您想要的結(jié)果。
BigInteger lower = new BigInteger("5");
BigInteger upper = new BigInteger("8");
BigInteger one = BigInteger.ONE, two = BigInteger.TWO;
BigInteger oneToUpper = upper.multiply(upper.add(one)).divide(two);
BigInteger oneToLower = lower.multiply(lower.add(one)).divide(two);
BigInteger lowertoUpperInc = oneToUpper.subtract(oneToLower).add(lower);
System.out.println(lowertoUpperInc); // 5 + 6 + 7 + 8 = 26
BigInteger lowertoUpperExc = oneToUpper.subtract(oneToLower).subtract(upper);
System.out.println(lowertoUpperExc); // 6 + 7 = 13
(請注意,您的循環(huán)似乎也返回18了這個示例,這似乎是您真正想要的5+6+7,因此不是您真正想要的。)
除了循環(huán)之外,這也適用于true BigInteger,例如 和 的總和(包含和排除)分別為lower = 123456789123456789和。upper = 987654321987654321480109740480109740075445815075445815480109740480109738964334703964334705

TA貢獻(xiàn)1859條經(jīng)驗 獲得超6個贊
正如另一個答案中已經(jīng)提到的:像這樣的電話
total.add(startingBoundary);
沒有任何可觀察到的影響。該add方法不會修改對象total。相反,它返回一個新 BigInteger對象。更一般地說,其原因是BigInteger不可變的。這意味著對象的值BigInteger在創(chuàng)建后就無法更改。至于原因,可以看一下為什么java中的BigInteger被設(shè)計成不可變的?
將行更改為
total = total.add(startingBoundary);
將解決這個問題(同樣,對于其他行 - 對于固定實現(xiàn),請參見下面的示例)。
旁注:您通常應(yīng)該使用and來代替new BigInteger("0")and 。沒有理由為這些常用值創(chuàng)建新對象。new BigInteger("1")BigInteger.ZEROBigInteger.ONE
不過,可能的改進(jìn)是:
除非作業(yè)明確指出必須用循環(huán)來解決這個問題,否則有一個更高效、更優(yōu)雅的解決方案。您可以使用Gau?'sche Summenformel(抱歉,沒有英文版本),它基本上指出:
1到n的自然數(shù)之和等于(n*(n+1))/2
因此,您可以在范圍的限制下直接計算這些總和,然后返回兩者之間的差值。
以下包含原始代碼的固定版本和替代實現(xiàn),以及(非常基本的)“微基準(zhǔn)”:
import java.math.BigInteger;
import java.util.Locale;
public class SumFromRange
{
public static void main(String[] args)
{
simpleExample();
simpleBenchmark();
}
private static void simpleExample()
{
System.out.println(addNumbers("5", "8"));
System.out.println(addNumbersFast("5", "8"));
System.out.println(addNumbers("15", "78"));
System.out.println(addNumbersFast("15", "78"));
}
private static void simpleBenchmark()
{
int blackHole = 0;
for (long min = 10000; min <= 20000; min += 10000)
{
for (long max = 10000000; max <= 20000000; max += 10000000)
{
String from = String.valueOf(min);
String to = String.valueOf(max);
long before = 0;
long after = 0;
before = System.nanoTime();
BigInteger slow = addNumbers(from, to);
after = System.nanoTime();
blackHole += slow.hashCode();
System.out.printf("Compute %10d to %10d slow took %8.3f ms\n",
min, max, (after - before) / 1e6);
before = System.nanoTime();
BigInteger fast = addNumbersFast(from, to);
after = System.nanoTime();
blackHole += fast.hashCode();
System.out.printf(Locale.ENGLISH,
"Compute %10d to %10d fast took %8.3f ms\n", min, max,
(after - before) / 1e6);
}
}
System.out.println("blackHole " + blackHole);
}
public static BigInteger addNumbers(String from, String to)
{
BigInteger total = BigInteger.ZERO;
BigInteger startingBoundary = new BigInteger(from);
BigInteger finishingBoundary = new BigInteger(to);
if (startingBoundary.compareTo(finishingBoundary) < 0)
{
startingBoundary = new BigInteger(from);
finishingBoundary = new BigInteger(to);
}
else
{
finishingBoundary = new BigInteger(from);
startingBoundary = new BigInteger(to);
}
startingBoundary = startingBoundary.add(BigInteger.ONE);
while (startingBoundary.compareTo(finishingBoundary) != 0)
{
total = total.add(startingBoundary);
startingBoundary = startingBoundary.add(BigInteger.ONE);
}
return total;
}
public static BigInteger addNumbersFast(String from, String to)
{
BigInteger f = new BigInteger(from);
BigInteger t = new BigInteger(to);
BigInteger sf = computeSum(f);
BigInteger st = computeSum(t.subtract(BigInteger.ONE));
return st.subtract(sf);
}
// Compute the sum of 1...n
public static BigInteger computeSum(BigInteger n)
{
BigInteger n1 = n.add(BigInteger.ONE);
return n.multiply(n1).divide(BigInteger.valueOf(2));
}
}
較大值的基準(zhǔn)結(jié)果是顯而易見的:
Compute 10000 to 10000000 slow took 635,506 ms
Compute 10000 to 10000000 fast took 0.089 ms
Compute 10000 to 20000000 slow took 1016,381 ms
Compute 10000 to 20000000 fast took 0.037 ms
Compute 20000 to 10000000 slow took 477,258 ms
Compute 20000 to 10000000 fast took 0.038 ms
Compute 20000 to 20000000 slow took 987,400 ms
Compute 20000 to 20000000 fast took 0.040 ms
這些根本就不是一個檔次的……

TA貢獻(xiàn)1835條經(jīng)驗 獲得超7個贊
使用
total = total.add(startingBoundary);
和
startingBoundary = startingBoundary.add(new BigInteger("1"));
因為add并不與第一個操作數(shù)相加,而是返回總和。
另外,在開始循環(huán)之前,執(zhí)行以下操作
startingBoundary = startingBoundary.add(new BigInteger("1"));
以滿足必須排除起始邊界的條件。
作為防御性編碼,不要使用等于零,而是使用
startingBoundary.compareTo(finishingBoundary) < 0
添加回答
舉報