【问题标题】:Code for Chi-square distribution function in DelphiDelphi中卡方分布函数的代码
【发布时间】:2018-05-17 15:14:34
【问题描述】:

我一直在寻找德尔福中chi-square 分发的可用且完整的代码。通过网络有一些代码,但通常它们不起作用或缺少部分,不编译等。还有一些库,但我对一些我可以简单实现的代码感兴趣。

我发现了一些几乎可以工作的东西。一些德语部分已修复,它编译并为大部分数据提供p-values

function LnGamma (x : Real) : Real;    
const 
  a0 =  0.083333333096; 
  a1 = -0.002777655457; 
  a2 =  0.000777830670; 
  c  =  0.918938533205;     
var  
  r : Real;     
begin 
  r := (a0 + (a1 + a2 / sqr(x)) / sqr(x)) / x; 
  LnGamma := (x - 0.5) * ln(x) - x + c + r; 
end; 

function LnFak (x : Real) : Real;     
var 
  z : Real;     
begin 
  z := x+1; 
  LnFak := LnGamma(z); 
end; 

function Reihe (chi : Real; f : Real) : Real;
  const MaxError = 0.0001;    
var
  Bruch,
  Summe,
  Summand : Real;
  k, i    : longint;    
begin
  Summe := 1;
  k := 1;
  repeat
    Bruch := 1;
    for i := 1 to k do
      Bruch := Bruch * (f + 2 * i);
    Summand := power(chi, 2 * k) / Bruch;
    Summe := Summe + Summand;
    k := succ(k);
  until (Summand < MaxError);
  Reihe := Summe;
end;

function IntegralChi (chisqr : Real; f : longint) : Real;
var
  s : Real;
begin
  S := power((0.5 * chisqr), f/2) * Reihe(sqrt(chisqr), f)
                  * exp((-chisqr/2) - LnGamma((f + 2) / 2));
  IntegralChi := 1 - s;
end;

它对于相对较大的结果非常有效。

例如:

对于Chi = 1.142132df = 1,我得到p 关于0.285202,这是完美的。与SPSS result 或其他程序相同。

但是例如Chi = 138.609137df = 4 我应该收到一些关于0.000000 的信息,但是我在Reiche 函数中遇到浮点溢出错误。 SummeSummand 那么很大。

我承认理解分布函数不是我的强项,所以也许有人会告诉我我做错了什么?

非常感谢您提供的信息

【问题讨论】:

  • 使用来自 netlib 的代码

标签: delphi statistics distribution chi-squared


【解决方案1】:

你应该调试你的程序,发现有溢出 在你的循环中 k=149。对于 k=148,Bruch 的值为 3.3976725289e+304。 Bruch 的下一次计算溢出。解决方法是编写代码

for i := 1 to k do
  Bruch := Bruch / (f + 2 * i);
Summand := power(chi, 2 * k) * Bruch;

通过此更改,您将在第 156 次迭代后获得值 IntegralChi(138.609137,4) = 1.76835197E-7

请注意,您的计算(即使对于这个简单的算法)是次优的 因为你一遍又一遍地计算布鲁赫值。只需更新一次 每个循环:

function Reihe (chi : Real; f : Real) : Real;
  const MaxError = 0.0001;
var
  Bruch,
  Summe,
  Summand : Real;
  k    : longint;
begin
  Summe := 1;
  k := 1;
  Bruch := 1;
  repeat
    Bruch := Bruch / (f + 2 * k);
    Summand := power(chi, 2 * k) * Bruch;
    Summe := Summe + Summand;
    k := succ(k);
  until (Summand < MaxError);
  Reihe := Summe;
end;

计算 power(chi, 2*k) 时应考虑类似的考虑,然后将其与 Bruch 的改进评估相结合。

编辑:作为对您评论的回应,这里是基于幂函数属性的改进版本,即power(chi, 2*(k+1)) = power(chi, 2*k)*sqr(chi)

function Reihe (chi : Real; f : Real) : Real;
  const MaxError = 0.0001;
var
  chi2,
  Summe,
  Summand : Real;
  k    : longint;
begin
  Summe := 1;
  k := 1;
  Summand := 1;
  chi2 := sqr(chi);
  repeat
    Summand := Summand * chi2 / (f + 2 * k);
    Summe := Summe + Summand;
    k := succ(k);
  until (Summand < MaxError);
  Reihe := Summe;
end;

【讨论】:

  • 非常感谢,您的解决方案完美运行。我已经检查了这个函数的 40 种不同 SPSS 结果的结果,并且完全兼容。但是,我并不完全理解这一点:“应该对计算能力(chi,2*k)应用类似的考虑,然后将其与改进的 Bruch 评估结合起来。”因为代码的这个元素已经被改进了?说到代码性能,我真的不需要。 :)
猜你喜欢
  • 2011-06-20
  • 2015-05-04
  • 1970-01-01
  • 2023-03-25
  • 2013-08-31
  • 1970-01-01
  • 1970-01-01
  • 2022-07-13
  • 1970-01-01
相关资源
最近更新 更多