你好我需要计算这个二项式系数
${2n \choose n} - {2n \choose n-1}$
对于大数字,我不知道如何使用数据类型LongWord
或QWord
。
有什么想法吗? :)
答案 0 :(得分:0)
在 Pascal 被设计的时代,对数和计算尺是工程师常用的工具,以至于导致包含一些基本的 logarithmic functions。
ln(i)
取正数的(自然)对数。 “自然”是指 e,欧拉常数。exp(i)
计算欧拉常数的 i
次方,eⁱ。您可以在一定程度上利用logarithmic identities来克服integer
的局限性。要使用二项式系数的阶乘公式,您可以编写:
type
integerNonNegative = 0..maxInt;
function factorialLn(n: integerNonNegative): real;
var
f: real value 0.0;
begin
for n := n downto 2 do
begin
f := f + ln(n);
end;
factorialLn := f;
end;
function binomialCoefficient(
protected n, k: integerNonNegative
): integerNonNegative;
begin
binomialCoefficient := round(exp(
factorialLn(n) -
(factorialLn(k) + factorialLn(n - k))
));
end;
我认为,这很棒,因为它不需要您使用/加载额外的库,而且不要忘记学习它。例如,GMP(GNU 多精度库)是 biiiiig,需要一些时间来深入了解它。这样你就可以简单地写
binomialCoefficient(2 * n, n) - binomialCoefficient(2 * n, n - 1)
然而,最好的方法当然是改进 你的 算法。在这种情况下,您对降低阶乘的幅度特别感兴趣。浏览一些公式我发现你的表情看起来很像
⎛ p − 1 ⎞ ⎛ p − 1 ⎞ p − 2 q ⎛ p ⎞
⎜ ⎟ − ⎜ ⎟ = ――――――― ⎜ ⎟
⎝ q ⎠ ⎝ q − 1 ⎠ p ⎝ q ⎠
所以你做了一些替换
p — 1 = 2 n │ + 1
p = 2 n + 1
在原来的等价物上展开
⎛ 2 n ⎞ ⎛ 2 n ⎞ 2 n + 1 − 2 n ⎛ 2 n + 1 ⎞
⎜ ⎟ − ⎜ ⎟ = ――――――――――――― ⎜ ⎟
⎝ n ⎠ ⎝ n − 1 ⎠ 2 n + 1 ⎝ n ⎠
现在我们得到了一个产品而不是一个差异,我们展开所有内容并合并它:
2 n + 1 − 2 n ⎛ 2 n + 1 ⎞ 1 (2 n + 1)!
――――――――――――― ⎜ ⎟ = ――――――― ―――――――――――――――――
2 n + 1 ⎝ n ⎠ 2 n + 1 n! (2 n + 1 − n)!
1 (2 n)! (2 n + 1) │
= ――――――― ――――――――――――――――― │ cancel 2n+1
2 n + 1 n! (n + 1)! │
(2 n)!
= ―――――――――――
n! (n + 1)!
2 n
∏ i
i = 1
= ―――――――――――――――――――――――
n
∏ i n! (n + 1)
i = 1
n 2 n
∏ i ∏ i
i = 1 i = n + 1
= ――――――――――――――――――――――――――
n
∏ i n! (n + 1)
i = 1
2 n
(n + 1) ∏ i
i = n + 2
= ――――――――――――――――――――――――――
(n + 1) n!
2 n
∏ i
i = n + 2
= ―――――――――――――
n!
另一方面,这表明我们只需要 n − 2
次迭代。换句话说,计算以下不需要对数引入的任何开销,但同样精确,而且不会超过 integer
的限制,最后但并非最不重要的是它更快:
r := 1.0;
for i := 2 to n do
begin
r := r / i * (n + i);
end;
writeLn(round(r));
这只是以程序风格编写的以下内容:
8! / 5! 6 ⋅ 7 ⋅ 8
――――――― = ―――――――――――――――――――――――――
3! 1 ⋅ 2 ⋅ 3
6 7 8
= ――― ⋅ ――― ⋅ ―――
1 2 3
整洁吧?