1: /// -------- ToujoursEnBeta
2: /// Author & Copyright : Peter Luschny
3: /// Created: 2010-03-01
4: /// License: LGPL version 2.1 or (at your option)
5: /// Creative Commons Attribution-ShareAlike 3.0
6:
7: using System;
8: using System.Collections.Generic;
9: using Xint = System.Numerics.BigInteger;
10:
11: namespace Combinatoricum {
12:
13: #region Swing
14:
15: public class Combinatorics
16: {
17: public Combinatorics() { }
18:
19: private Primes prime;
20: private Factors factors;
21:
22: // OEIS: A056040 Swinging factorial
23: public Xint Swing(uint n)
24: {
25: if (n >= smallOddSwing.Length)
26: {
27: prime = new Primes(n);
28: factors = new Factors(n);
29: }
30: return OddSwing(n) << (int)MathFun.BitCount(n);
31: }
32:
33: private Xint OddSwing(uint n)
34: {
35: if (n < smallOddSwing.Length) return smallOddSwing[n];
36:
37: uint rootN = MathFun.FloorSqrt(n);
38: factors.Init();
39:
40: factors.SetMax(rootN);
41: prime.Factorizer(3, rootN, p =>
42: {
43: uint q = n;
44: while ((q /= p) > 0)
45: if ((q & 1) == 1) { factors.Add(p); }
46: });
47:
48: factors.SetMax(n / 3);
49: prime.Factorizer(rootN + 1, n / 3, p =>
50: {
51: if (((n / p) & 1) == 1) { factors.Add(p); }
52: });
53:
54: factors.SetMax(n);
55: prime.Factorizer(n / 2 + 1, n, p =>
56: {
57: factors.Add(p);
58: });
59:
60: return factors.Product();
61: }
62:
63: #endregion
64: #region factorial
65:
66: // OEIS: A000142 Factorial
67: public Xint Factorial(uint n)
68: {
69: int exp2 = (int)(n - MathFun.BitCount(n));
70:
71: if (n < smallOddFactorial.Length)
72: return new Xint(smallOddFactorial[n]) << exp2;
73:
74: if (n >= smallOddSwing.Length)
75: {
76: prime = new Primes(n);
77: factors = new Factors(n);
78: }
79:
80: return OddFactorial(n) << exp2;
81: }
82:
83: private Xint OddFactorial(uint n)
84: {
85: if (n < smallOddFactorial.Length)
86: {
87: return smallOddFactorial[n];
88: }
89:
90: return Xint.Pow(OddFactorial(n / 2), 2) * OddSwing(n);
91: }
92:
93: #endregion
94: #region binomial
95:
96: // OEIS: A007318 Pascal's triangle
97: public Xint Binomial(uint n, uint k)
98: {
99: if (0 > k || k > n) return Xint.Zero;
100: if (k > n / 2) { k = n - k; }
101: if (k < 3)
102: {
103: if (k == 0) return Xint.One;
104: if (k == 1) return new Xint(n);
105: if (k == 2) return new Xint(((ulong)n * (n - 1)) / 2);
106: }
107: if (n == 2 * k) { return Swing(n); }
108:
109: var prime = new Primes(n);
110: var factors = new Factors(n);
111:
112: uint rootN = MathFun.FloorSqrt(n);
113: factors.Init();
114:
115: factors.SetMax(rootN);
116: prime.Factorizer(2, rootN, p =>
117: {
118: uint r = 0, N = n, K = k;
119: while (N > 0)
120: {
121: r = (N % p) < (K % p + r) ? 1u : 0u;
122: if (r == 1)
123: {
124: factors.Add(p);
125: }
126: N /= p; K /= p;
127: }
128: });
129:
130: factors.SetMax(n / 2);
131: prime.Factorizer(rootN + 1, n / 2, p =>
132: {
133: if (n % p < k % p)
134: {
135: factors.Add(p);
136: }
137: });
138:
139: factors.SetMax(n);
140: prime.Factorizer(n - k + 1, n, p =>
141: {
142: factors.Add(p);
143: });
144:
145: return factors.Product();
146: }
147:
148: #endregion
149: #region doublefactorial
150:
151: // OEIS: A006882 Double factorials n!!: a(n) = n*a(n-2).
152: public Xint DoubleFactorial(uint n)
153: {
154: Xint dblFact;
155: uint N = ((n & 1) == 0) ? n / 2 : n + 1;
156:
157: if (n < smallOddDoubleFactorial.Length)
158: {
159: dblFact = (Xint)smallOddDoubleFactorial[n];
160: }
161: else
162: {
163: if (N >= smallOddSwing.Length)
164: {
165: prime = new Primes(N);
166: factors = new Factors(N);
167: }
168: dblFact = OddFactorial(N, n);
169: }
170:
171: if ((n & 1) == 0)
172: {
173: int exp2 = (int)(n - MathFun.BitCount(n / 2));
174: dblFact = dblFact << exp2;
175: }
176: return dblFact;
177: }
178:
179: private Xint OddFactorial(uint n, uint m)
180: {
181: if (n < smallOddFactorial.Length)
182: {
183: return smallOddFactorial[n];
184: }
185:
186: Xint oddFact = OddFactorial(n / 2, m);
187: if (n < m)
188: {
189: oddFact = Xint.Pow(oddFact, 2);
190: }
191:
192: return oddFact * OddSwing(n);
193: }
194:
195: private static ulong[] smallOddSwing = {
196: 1, 1, 1, 3, 3, 15, 5, 35, 35, 315, 63, 693, 231, 3003, 429, 6435, 6435,
197: 109395, 12155, 230945, 46189, 969969, 88179, 2028117, 676039, 16900975,
198: 1300075, 35102025, 5014575, 145422675, 9694845, 300540195, 300540195,
199: 9917826435, 583401555, 20419054425, 2268783825, 83945001525, 4418157975,
200: 172308161025, 34461632205, 1412926920405, 67282234305, 2893136075115,
201: 263012370465, 11835556670925, 514589420475, 24185702762325, 8061900920775,
202: 395033145117975, 15801325804719, 805867616040669, 61989816618513,
203: 3285460280781189, 121683714103007, 6692604275665385, 956086325095055,
204: 54496920530418135, 1879204156221315, 110873045217057585, 7391536347803839,
205: 450883717216034179, 14544636039226909, 916312070471295267, 916312070471295267 };
206:
207: private static ulong[] smallOddFactorial = {
208: 1, 1, 1, 3, 3, 15, 45, 315, 315, 2835, 14175, 155925, 467775, 6081075,
209: 42567525, 638512875, 638512875, 10854718875, 97692469875, 1856156927625,
210: 9280784638125, 194896477400625, 2143861251406875, 49308808782358125,
211: 147926426347074375, 3698160658676859375 };
212:
213: private static ulong[] smallOddDoubleFactorial = {
214: 1, 1, 1, 3, 1, 15, 3, 105, 3, 945, 15, 10395, 45, 135135, 315, 2027025, 315,
215: 34459425, 2835, 654729075, 14175, 13749310575, 155925, 316234143225, 467775,
216: 7905853580625, 6081075, 213458046676875, 42567525, 6190283353629375, 638512875,
217: 191898783962510625, 638512875, 6332659870762850625, 10854718875 };
218: }
219:
220: #endregion
221: #region primes
222:
223: // OEIS: A000040 prime number
224: public class Primes
225: {
226: const int bitsPerInt = 32;
227: const int mask = bitsPerInt - 1;
228: const int log2Int = 5;
229:
230: private static uint[] PrimesOnBits = {
231: 1762821248u, 848611808u, 3299549660u, 2510511646u };
232:
233: private uint[] isComposite;
234: public delegate void Visitor(uint x); // aka function pointer
235:
236: public void Factorizer(uint min, uint max, Visitor visitor)
237: {
238: // isComposite[0] ... isComposite[n] includes
239: // 5 <= prime numbers <= 96*(n+1) + 1
240:
241: if (min <= 2) visitor(2);
242: if (min <= 3) visitor(3);
243:
244: int absPos = (int)((min + (min + 1) % 2) / 3 - 1);
245: int index = absPos / bitsPerInt;
246: int bitPos = absPos % bitsPerInt;
247: bool toggle = (bitPos & 1) == 1;
248: uint prime = (uint)(5 + 3 * (bitsPerInt * index + bitPos) - (bitPos & 1));
249:
250: while (prime <= max)
251: {
252: uint bitField = isComposite[index++] >> bitPos;
253: for (; bitPos < bitsPerInt; bitPos++)
254: {
255: if ((bitField & 1) == 0)
256: {
257: visitor(prime);
258: }
259: prime += (toggle = !toggle) ? 2u : 4u;
260: if (prime > max) return;
261: bitField >>= 1;
262: }
263: bitPos = 0;
264: }
265: }
266:
267: /// Prime number sieve, Eratosthenes (276-194 b. bitPos.)
268: /// This implementation considers only multiples of primes
269: /// greater than 3, so the smallest value has to be mapped to 5.
270: /// Note: There is no multiplication operation in this function
271: /// and *no call to a sqrt* function.
272:
273: public Primes(uint n)
274: {
275: if (n < 386) { isComposite = PrimesOnBits; return; }
276:
277: isComposite = new uint[(n / (3 * bitsPerInt)) + 1];
278: int d1 = 8, d2 = 8, p1 = 3, p2 = 7, s = 7, s2 = 3;
279: int l = 0, c = 1, max = (int)n / 3, inc;
280: bool toggle = false;
281:
282: while (s < max) // -- scan the sieve
283: {
284: // -- if a prime is found ...
285: if ((isComposite[l >> log2Int] & (1u << (l++ & mask))) == 0)
286: {
287: inc = p1 + p2; // -- ... cancel its multiples
288: for (c = s; c < max; c += inc)
289: { // -- ... set c as composite
290: isComposite[c >> log2Int] |= 1u << (c & mask);
291: }
292:
293: for (c = s + s2; c < max; c += inc)
294: {
295: isComposite[c >> log2Int] |= 1u << (c & mask);
296: }
297: }
298:
299: if (toggle = !toggle) { s += d2; d1 += 16; p1 += 2; p2 += 2; s2 = p2; }
300: else { s += d1; d2 += 8; p1 += 2; p2 += 6; s2 = p1; }
301: }
302: }
303: }
304:
305: #endregion
306: #region support
307:
308: class Factors
309: {
310: private ulong[] factors;
311: private ulong maxProd, prod;
312: private int count;
313:
314: public Factors(uint n)
315: {
316: int mem = (int)(0.63 * n / Math.Log(n));
317: factors = new ulong[mem];
318: }
319:
320: public void Init()
321: {
322: maxProd = 1;
323: prod = 1;
324: count = 0;
325: }
326:
327: public void SetMax(ulong max)
328: {
329: maxProd = ulong.MaxValue / max;
330:
331: if (prod >= maxProd)
332: {
333: factors[count++] = prod;
334: prod = 1;
335: }
336: }
337:
338: public void Add(ulong prime)
339: {
340: if (prod < maxProd) // I learned this clever idea
341: { // from Marco Bodrato.
342: prod *= prime;
343: }
344: else
345: {
346: factors[count++] = prod;
347: prod = prime;
348: }
349: }
350:
351: public Xint Product()
352: {
353: factors[count++] = prod;
354: return MathFun.Product(factors, 0, count);
355: }
356: }
357:
358: public class MathFun
359: {
360: // Calibrate to a Karatsuba treshhold
361: private const int THRESHOLD_PRODUCT_SERIAL = 24;
362:
363: static public Xint ProductSerial(ulong[] seq, int start, int len)
364: {
365: var prod = new Xint(seq[start]);
366:
367: for (int i = start + 1; i < start + len; i++)
368: {
369: prod *= seq[i];
370: }
371:
372: return prod;
373: }
374:
375: static public Xint Product(ulong[] seq, int start, int len)
376: {
377: if (len <= THRESHOLD_PRODUCT_SERIAL)
378: {
379: return ProductSerial(seq, start, len);
380: }
381:
382: int halfLen = len / 2;
383: return Product(seq, start, halfLen) *
384: Product(seq, start + halfLen, len - halfLen);
385: }
386:
387: /// Bit count,
388: /// sometimes referred to as the population count.
389: public static uint BitCount(uint w)
390: {
391: w = w - ((0xaaaaaaaa & w) >> 1);
392: w = (w & 0x33333333) + ((w >> 2) & 0x33333333);
393: w = w + (w >> 4) & 0x0f0f0f0f;
394: w += w >> 8;
395: w += w >> 16;
396:
397: return w & 0xff;
398: }
399:
400: public static uint FloorSqrt(uint n)
401: {
402: uint a, b;
403: a = b = n;
404: do
405: {
406: a = b;
407: b = (n / a + a) / 2;
408: } while (b < a);
409: return a;
410: }
411:
412: private MathFun() { }
413: }
414:
415: #endregion
416: #region test
417:
418: class Test
419: {
420: static void Main()
421: {
422: var combi = new Combinatorics();
423:
424: var swing = combi.Swing(1000);
425: System.Console.WriteLine("Swing: " + swing);
426:
427: var fact = combi.Factorial(1000);
428: System.Console.WriteLine("Factorial: " + fact);
429:
430: var dblfact = combi.DoubleFactorial(1000);
431: System.Console.WriteLine("DoubleFactorial: " + dblfact);
432:
433: var pascal = combi.Binomial(1000, 333);
434: System.Console.WriteLine("Binomial: " + pascal);
435:
436: System.Console.ReadLine();
437: }
438: }
439:
440: #endregion
441: }