We need the input number as the sum of consecutive natural numbers.
Examples:
For input 27, output should be:
2 3 4 5 6 7
8 9 10
13 14
For input 9, the output should be:
4 5
2 3 4
Here is my code. It works as it is expected to:
import java.util.*;
class Consecutives
{
static void print()
{
Scanner sc = new Scanner(System.in);
System.out.println("Enter number: ");
double n = sc.nextDouble();
/*
* Needed: Different Arithmetic progressions (APs) with common difference 1;
* i(2a + (i-1)) = 2n // from formula for sum of AP, a indicates first term of progression
* #implies -> a = n/i - (i-1)/2 // i indicates number of terms of AP possible
* Now, a can't be negative so:
* -> n/i > (i-1)/2
* -> Range of i = [2, (int)(1+sqrt(1+8n))/2]
*/
int max_i = (int)((1+Math.sqrt(1+8*n))/2);
System.out.println("Max i = "+ max_i);
double a;
for(double i=2; i <= max_i ;i++)
{
a = n/i - (i-1)/2;
if(a == Math.floor(a) && a>0)//i.e if a is an integer
{
if(i*(2*a+ (i-1))== 2*n)
{
for(int j= (int)a ; j<=a + (i-1) ;j++)
System.out.print(j+ " ");
System.out.println();
}
else
break;
}
}
}
}
Are my comments too messy? Is there any way to change them and still make the logic clear to the reader? What other improvements can I make to my program?
1 Answer 1
Your algorithm, being \$O(\sqrt n)\,ドル is pretty efficient. I just think that your code could just a bit of cleanup.
Your print()
function does all kinds of things, mostly unrelated to printing. You should separate the code for the user interaction from the calculation. (Since each result is a pair of numbers, and there will be an indeterminate number of results, I'd use a callback.) You should also extract the loop the prints each series into a helper function. (Executing many System.out.print()
statements can be surprisingly slow, as each one is a separate I/O operation.)
Your mathematical reasoning was not clear to me at first. I would have preferred a comment that more clearly explained the nomenclature and used fewer words.
// n = a + (a+1) + ... + (a+i-1) (Given n, find all a>0 and i>=2)
//
// 2n = i(2a + (i-1)) (arithmetic series formula)
//
// a = (2n - i(i-1)) / 2i
//
// 2n > i(i-1) (because a>0 and i>0)
//
// 2 <= i < (1+sqrt(1+8n))/2 (quadratic formula)
Since this is supposed to be an exercise in integer arithmetic, you should avoid using doubles. Use either int
or long
. Note that I have avoided your a = n/i - (i-1)/2
, which involves non-integer division.
Actually, you don't need to calculate max_i
. You don't really trust that bound, and you test for a > 0
anyway.
Suggested solution
import java.util.Scanner;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;
import java.util.stream.LongStream;
public class Consecutives {
/**
* Find integers a>0 and i>=2 such that n = a + (a+1) + ... + (a+i-1).
*
* @param n The target sum.
* @param callback A function that will be called with parameters a and i
* for each solution found.
*/
public static void findSeries(long n, BiConsumer<Long, Long> callback) {
// n = a + (a+1) + ... + (a+i-1) (Given n, find all a>0 and i>=2)
//
// 2n = i(2a + (i-1)) (arithmetic series formula)
//
// a = (2n - i(i-1)) / 2i
for (long i = 2; ; i++) {
long aNumer = 2 * n - i * (i - 1);
long aDenom = 2 * i;
if (aNumer <= 0) break;
if (aNumer % aDenom == 0) {
callback.accept(aNumer / aDenom, i);
}
}
}
/**
* Form a string of all integers in the range [a, a+i), separated by space.
*/
private static String spaceDelimitedRange(long a, long i) {
return LongStream.range(a, a+i)
.mapToObj(String::valueOf)
.collect(Collectors.joining(" "));
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("Enter number: ");
findSeries(
scanner.nextLong(),
(a, i) -> System.out.println(spaceDelimitedRange(a, i))
);
}
}
-
\$\begingroup\$ Thanks for the answer. Which part of my mathematical reasoning isn't clear? Please let me know so that I can elaborate upon that. \$\endgroup\$Archer– Archer2018年09月01日 00:04:47 +00:00Commented Sep 1, 2018 at 0:04
-
\$\begingroup\$ I've made an effort to understand your reasoning, and completely rewrote my review in Rev 2. \$\endgroup\$200_success– 200_success2018年09月01日 01:01:06 +00:00Commented Sep 1, 2018 at 1:01