Вот такая порнография получается, если не использовать стандартное разложение на простые множители:
import java.util.*;
public class Test_Binomial_3 {
private static final int LIMIT = 500_000;
// private static final int LIMIT = 200;
private static final int [] mulsPower = new int [LIMIT + 1];
private static final int [] divsPower = new int [LIMIT / 2 + 1];
public static void main (String [] args) {
int k, l, m, setSize, subSize, val, divPower;
double logResult = 0.0;
Random rand = new Random ();
val = (int) (2 * Math .sqrt (LIMIT));
setSize = LIMIT - rand .nextInt (val);
subSize = rand .nextInt (setSize / 2 - val) + val + 1;
//setSize = 50;
//subSize = 22;
//setSize = 43;
//subSize = 20;
//setSize = 49;
//subSize = 16;
System .out .println ("n = " + setSize + ", k = " + subSize + "\n");
Arrays .fill (mulsPower, 0);
for (k = setSize - subSize + 1; setSize >= k; ++k) {
mulsPower [k] = 1;
}
Arrays .fill (divsPower, 0);
for (k = 2; subSize >= k; ++k) {
divsPower [k] = 1;
}
outerLoop:
for (k = subSize; 2 <= k; --k) {
//display (setSize, subSize);
//System .out .println ("div = " + k);
divPower = divsPower [k];
if (0 == divPower) {
continue;
}
val = Integer .min (divPower, mulsPower [k]);
mulsPower [k] -= val;
divPower -= val;
if (0 == divPower) {
divsPower [k] = 0;
continue;
}
for (l = 2; k >= l * l; ++l) {
if (0 != k % l) {
continue;
}
m = k / l;
val = Integer .min (divPower, mulsPower [m]);
mulsPower [m] -= val;
divsPower [l] += val;
divPower -= val;
if (0 == divPower) {
divsPower [k] = 0;
continue outerLoop;
}
if (m == l) {
continue;
}
val = Integer .min (divPower, mulsPower [l]);
mulsPower [l] -= val;
divsPower [m] += val;
divPower -= val;
if (0 == divPower) {
divsPower [k] = 0;
continue outerLoop;
}
}
for (l = setSize / k, m = l * k; 2 <= l; --l, m -= k) {
val = Integer .min (divPower, mulsPower [m]);
mulsPower [m] -= val;
mulsPower [l] += val;
divPower -= val;
if (0 == divPower) {
divsPower [k] = 0;
continue outerLoop;
}
}
val = Integer .min (divPower, mulsPower [k]);
mulsPower [k] -= val;
divPower -= val;
if (0 == divPower) {
divsPower [k] = 0;
continue;
}
System .out .print ("GCD for " + k);
for (l = 4; setSize > l; ++l) {
if (0 == mulsPower [l]) {
continue;
}
val = gcd (k, l);
if (1 == val) {
continue;
}
val = Integer .min (val, k / val);
System .out .println (" with " + l + " by " + val);
divsPower [k] = divPower;
for (l = k / val, m = k; 2 <= l; --l, m -= val) {
divPower = divsPower [m];
divsPower [m] = 0;
divsPower [l] += divPower;
divsPower [val] += divPower;
}
continue outerLoop;
}
System .out .println (" - ERROR !");
}
//display (setSize, subSize);
System .out .println ("\nDone.\n");
for (k = 2, l = 0; setSize > k; ++k) {
val = mulsPower [k];
l += val;
logResult += val * Math .log10 (k);
}
val = (int) Math .floor (logResult);
System .out .println ("Result: " + Math .pow (10, logResult - val) + " * 10 ^ " + val);
System .out .println ("Number of multipliers: " + l);
}
@SuppressWarnings ("unused")
private static void display (int setSize, int subSize) {
int k;
for (k = 2; subSize >= k; ++k) {
System .out .println (String .format ("%6d%6d%6d", k, mulsPower [k], divsPower [k]));
}
for (; setSize >= k; ++k) {
System .out .println (String .format ("%6d%6d", k, mulsPower [k]));
}
}
private static int gcd (int a, int b) {
while (0 != b) {
int c = b;
b = a % b;
a = c;
}
return a;
}
}
Числитель
, представленный в виде множителей последовательных чисел в степенях, хранимых в переменной
mulsPower, сокращается со знаменателем
, степени которого хранятся в
divsPower. Формально разложение на простые множители отсутствует, но оно неявно происходит, когда очередной обрабатываемых множитель делителя не сокращается ни с одним множителем делимого. Это означает, что этот делящий множитель составной, и, с помощью поиска наибольшего общего делителя (функция
gcd), этот делящий множитель раскладывается на сомножители (а за одно и все остальные, меньшее его и имеющие тот же самый делитель).
Программа не находит функцию Эйлера, только представление её аргумента в виде "маленьких" множителей. Для завершения, нужно добавить таблицу простых чисел, поиск простых сомножителей и собственно расчёт по формуле
Результат работы программы сейчас приблизительно выглядит так:
n = 498691, k = 241303
GCD for 128690 with 257390 by 10
GCD for 128686 with 257390 by 2
GCD for 64347 with 257391 by 3
GCD for 20699 with 14 by 7
GCD for 13211 with 22 by 11
GCD for 11219 with 26 by 13
GCD for 7633 with 34 by 17
GCD for 6289 with 38 by 19
GCD for 5267 with 46 by 23
GCD for 4321 with 58 by 29
GCD for 4061 with 62 by 31
Done.
Result: 4.233477958222776 * 10 ^ 149999
Number of multipliers: 28221
Фактически получается алгоритм по ходу дела калибрует, какие простые числа использовать для расщепления делителя на меньшие множители.