Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/307.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/html/75.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何使用biginteger对两个边界之间的数字求和_Java_Biginteger - Fatal编程技术网

Java 如何使用biginteger对两个边界之间的数字求和

Java 如何使用biginteger对两个边界之间的数字求和,java,biginteger,Java,Biginteger,我试图将两个给定数字之间的所有数字相加,不包括边界。。例如,addNumbers5、8应该返回13,因为6+7=13。这是我目前拥有的功能 public static BigInteger addNumbers(String from, String to) { BigInteger total = new BigInteger("0"); BigInteger startingBoundary = new BigInteger(from); BigInteger finishin

我试图将两个给定数字之间的所有数字相加,不包括边界。。例如,addNumbers5、8应该返回13,因为6+7=13。这是我目前拥有的功能

 public static BigInteger addNumbers(String from, String to) {
  BigInteger total = new BigInteger("0");
  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);
  }

  while (startingBoundary.compareTo(finishingBoundary) != 0 )  {
     System.out.println("Starting boundary:" + startingBoundary.intValue());
     System.out.println("Finishing boundary: " + finishingBoundary.intValue());

     total.add(startingBoundary);
     System.out.println("total: "+total.intValue());

     startingBoundary.add(new BigInteger("1"));
  }
  return total;
}

问题是,尽管我更改了while条件的值,但它似乎无限运行。另外,当打印出每个循环中的总对象时,它总是打印出0。我知道我将其初始化为0,但我希望在添加时它会发生更改

使用

total = total.add(startingBoundary);

因为add不向第一个操作数相加,而是返回和

此外,在开始循环之前,请执行以下操作

startingBoundary = startingBoundary.add(new BigInteger("1"));
以满足必须排除起始边界的条件

作为防御性编码,不要使用等于零,而是使用

startingBoundary.compareTo(finishingBoundary) < 0
请注意,使用BigInteger意味着数字以及两个数字之间的差异可能很大。从下边界到上边界的循环可能需要很长时间。相反,您可以使用封闭形式sum1..N=N*N+1/2的变体。使用它将数字从1到上限和从1到下限相加,然后将两者合并以获得所需的结果

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
注意,对于这个例子,您的循环似乎也返回18,它似乎是5+6+7,因此不是您真正想要的


除了您的循环,这也适用于真正的BigInteger,例如,lower=123456789123456789和upper=987654321987654321的包含和排除的和分别是480109740480109740075445815075445815和48010974048010973964334705。

如另一个答案中所述:类似的调用

total.add(startingBoundary);
没有任何明显的效果。add方法不修改total对象。相反,它返回一个新的BigInteger对象。原因是,更一般地说,BigInteger是不可变的。这意味着BigInteger对象的值在创建后无法更改。出于这些原因,请看一看

将线路更改为

total = total.add(startingBoundary);
将以类似方式解决此问题,对于其他行-对于固定的实现,请参见下面的示例

旁注:通常应该使用biginger.ZERO和biginger.ONE,而不是新的biginger.0和新的biginger.1。没有理由为这些常用值创建新对象

但可能的改进是:

除非任务明确指出这必须通过循环来解决,否则有一个更高效、更优雅的解决方案。你可以用抱歉,没有英文版本的,基本上是这样的

从1到n的自然数之和等于n*n+1/2

所以你可以直接计算这些总和,在你的范围内,然后返回两者之间的差值

以下包含原始代码的固定版本和替代实现,以及非常基本的微基准:

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));
    }

}

它们甚至不属于同一类…

请注意,您第一次指定的startingBoundary和finishingBoundary是无用的,因为您在if/else中为它们指定了新对象。请注意,BigInteger意味着这两个数字之间的差异可能很大。从下边界到上边界的循环可能需要很长时间。相反,您可以使用封闭形式sum1..N=N*N+1/2的变体。您应该使用BigInteger.valueOf而不是新的BigInteger,因为前者允许缓存经常使用的值。@tobias_k我试图解决您对循环工作的担忧。是的,您修复了在循环中工作的问题,但是循环本身也是一个问题。对于较大的数字和大整数意味着较大的数字,这太慢了。你可以使用求和公式n*n+1/2,但这不是相同的练习。此外,可以使用增量运算符,而不是每个循环创建一个值为1的新BigInteger。好吧,我们不知道这个练习是什么,如果OP应该使用循环,或者即使OP应该使用BigInteger。如果上下限相隔几十亿或几十亿,那么这个循环将运行得非常非常长。不,n*n+1/2的想法也是一样,但我花了几分钟时间研究了一个无用的基准:-/
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));
    }

}
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