The question is ambiguous as to whether square root is allowed, does it strictly count as an arithmetic operation?
If we assume its not allowed and we cannot use any looping we can use Newton's method to give a good approximation to the answer. Others have pointed out that we are basically trying the find the inverse of the triangular numbers T(n)=n(n+1)/2
. If we are given a sum S
let f(n)=n^2/2+n/2-S
we want to solve f(n)=0
. Newton's method is a fast iterative method, given an initial guess x0 we can find a better guess x1 using
x1 = x0 - f(x) / df(x)
where df(x)=x-1/2
is the derivative. If we do this 4 times we get a pretty good solution.
public class InverseSqrt {
static float f(float x,float S) {
return x*x/2+x/2-S;
}
static float df(float x,float S) {
return x+0.5f;
}
static float newton(float sum) {
float x = sum/2; // first initial guess
// Apply Newton's method four time
x = x - f(x,sum) / df(x,sum);
x = x - f(x,sum) / df(x,sum);
x = x - f(x,sum) / df(x,sum);
x = x - f(x,sum) / df(x,sum);
return x;
}
public static void main(String[] args) {
int i=0;
int ires=0;
do { // loop through possible number of goals
++i;
float s = i * (i+1) * 0.5f; // calculate the total
float res = newton(s);
ires = (int) (res+0.5); // round to nearest integer
System.out.print("T("+i+")="+(int)s);
System.out.println("\tres="+ires+"\t("+res+")");
} while(ires==i); // break first time it fails
}
}
This works pretty well up to an input of 351 giving an output of 26. But fails for the next input 378 giving 28 rather than 27 goal.
We can improve things a bit by using 5 steps of Newtons method working up to an input of 1176 with an output of 48. Tuning the initial guess improves things dramatically, using a starting guess of n/16 with 5 steps works upto input 42195 output 290.
A much better solution can be found using the Fast inverse squareroot. This can be implemented in Java following this answer.
static float Q_rsqrt( float x )
{
float xhalf = 0.5f*x;
int i = Float.floatToIntBits(x);
i = 0x5f3759df - (i>>1);
x = Float.intBitsToFloat(i);
x = x*(1.5f - xhalf*x*x);
return x;
}
Our Newton iteration method is then
static float newton(float sum) {
float x = Q_rsqrt(1/sum);
x = x - f(x,sum) / df(x,sum);
x = x - f(x,sum) / df(x,sum);
x = x - f(x,sum) / df(x,sum);
return x;
}
with only 3 iteration steps.
This works upto Input 1073720960 Output 46340. The next item after than gives an integer overflow in calculating the sum, so it can be said to work for all legal int values.
This might not be counted as a legal solution as it uses floatToIntBits(x)
and intBitsToFloat(x)
which don't really class as arithmetic operations.