This is a problem from CodeSprint3 https://cs3.interviewstreet.com/challenges/dashboard/#problem/50877a587c389 Basically the problem is to calculate the number of possible combinations,nCr for given n and r.Also, 1 <= n <= 1000000000 and 0 <= r <= n. Output all answers modulo 142857.
Since 6C4=6!/4! 2!
=6*5/2!
=6*5/2*1
I thought overflow could be avoided using division at every step.That is to start with value of n (n is 6 in this case). Decrement n and multiply it with previous value (so this becomes 6*5) Perform division with denominator and then decrement it ( 6*5 /2 and denominator 2 becomes 1) Repeat the steps until n is less than the of maximum of 2 denominators and in same number of iterations the divisor (Minimum of denominators will become 1)
int count(int n,int r)
{int maxDen=r>(n-r)?r:n-r; //larger number in the denominator
int minDen=n-maxDen; //the smaller number in denominator
double num=1;
for(int j=n;j>maxDen;j--)
{num=j*num; //for C(6,4) example num=6*5 and so on
// System.out.println("num "+num +" minDen "+minDen);
num=num/minDen; //divide num 6*5 in this case by 2
minDen--;
}
num=num%142875; //output the result modulo 142875
return (int) num;
}
But perhaps due to loss precision as more divisions are performed,it gives wrong values but then it still gives correct output for some values.As it stands correct for 22 17 but not for 24 17.
(22 17) = 26334 //gives Correct value
(24 17)= 60353 //wrong value correct value is 60390
(25,17)=81450 //wrong value correct value is 81576
(16 15)= 16 //gives correct value
(87 28)= 54384 //wrong value correct value is 141525
I tried to use num as a BigDecimal and as a consequence i had to replace everything with a BigDecimal to perform the operations.The output then was the same for the inputs which gave correct results in above code.But for inputs which gave wrong results,the program throws an exception
Exception in thread "main" **java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.**
at java.math.BigDecimal.divide(Unknown Source)
at Combination.NcRcount2.count(NcRcount2.java:16)
at Combination.NcRcount2.main(NcRcount2.java:37)
Line 16 is num=num.divide(minDen); //in replacement to earlier used num/minDen,both num and minDen are BigDecimal in this case
Even though if the number does not have an exact decimal representation,given the arbitrary precision of BigDecimal the error in results would have been minimized if it didn't threw an exception. ** If the result of division on floats or doubles does not have an exact decimal representation then why isn't an exception thrown?**
I verified the results using BigDecimal with the dynamic programming approach as
C(n,r)=C(n-1,r-1)+C(n-1,r)
This works correctly in all cases as it appears to me but there must be a better way
BigDecimal Comb (int n, int k)
{ if(k>n-k)
k=n-k;
BigDecimal B[][]=new BigDecimal[n+1] [k+1];
for (int i = 0; i <= n; i++)
{ int min;
if(i>=k)
min=k;
else
min=i;
for (int j = 0; j <= min; j++)
{ if (j == 0 || j == i)
B[i][j] =new BigDecimal(1);
else{
if(j>i-j)
B[i][j]=B[i][i-j];
else
B[i][j] = B[i - 1][j - 1].add(B[i - 1] [j]);
}
}
}
BigDecimal div=new BigDecimal(142857);
return B[n][k].remainder(div);
}
Please suggest me a better way to do this without using BigDecimal