I'm trying to use double-checked locking to maintain an array of binomial coefficients, but I read recently that double-checked locking doesn't work. Efficiency is extremely important so using volatile isn't an option unless it's only inside the conditional statements. I can't see a way to use a static class with a singleton object (this is part of a framework and I don't know what kinds of numbers people will need to use the function for so I can't guess what the maximum chosen value will be or whether the function will be used at all). The only thing I can think of is to make everything not static and insist that each thread that needs to use this method instantiate a Choose object with its own array. It seems like that shouldn't be necessary.
public static final class Util{
/**
* Static array of nCr values
*/
public static long[][] nCr_arr;
/**
* Calculate binomial coefficient (n k)
*
* @param n
* n
* @param k
* k
* @return n choose k
*/
public static long nCr(int n, int k) {
if (k < 0)
throw new ArithmeticException("Cannot choose a negative number");
if (n < 0) {
if (k % 2 == 0)
return nCr(-n + k - 1, k);
else
return -nCr(-n + k - 1, k);
}
if (k > n)
return 0;
if (k > n / 2)
k = n - k;
if (nCr_arr == null) {
synchronized (Util.class) {
if (nCr_arr == null)
nCr_arr = new long[n + 1][];
}
}
if (nCr_arr.length <= n) {
synchronized (Util.class) {
if (nCr_arr.length <= n) {
long[][] newNCR = new long[n + 1][];
System.arraycopy(nCr_arr, 0, newNCR, 0, nCr_arr.length);
nCr_arr = newNCR;
}
}
}
if (nCr_arr[n] == null) {
synchronized (Util.class) {
if (nCr_arr[n] == null)
nCr_arr[n] = new long[k + 1];
}
}
if (nCr_arr[n].length <= k) {
synchronized (Util.class) {
if (nCr_arr[n].length <= k) {
long[] newNCR = new long[k + 1];
System.arraycopy(nCr_arr[n], 0, newNCR, 0,
nCr_arr[n].length);
nCr_arr[n] = newNCR;
}
}
}
if (nCr_arr[n][k] == 0) {
if (k == 0)
nCr_arr[n][k] = 1;
else
nCr_arr[n][k] = nCr(n, k - 1) * (n - (k - 1)) / k;
}
return nCr_arr[n][k];
}
}