我们如何在Oracle SQL或PL / SQL中实现标准普通CDF?

时间:2017-07-31 13:15:32

标签: sql oracle plsql oracle11g

如何使用Oracle SQL或PL / SQL实现以下功能?

Refer

3 个答案:

答案 0 :(得分:2)

这个存储过程给出的结果与 Calc 中的 NORMDIST 函数相同。 需要传递的参数有x、均值、标准差和累积。 累积参数可以选择在 x (0) 处获得正态分布值或值<=x (1) 的累积概率。

create or replace FUNCTION NORMDIST(x_value number,mean_value number,stddev_value number, cumulative NUMBER DEFAULT 0)
RETURN NUMBER IS

        x number;
        t number;
        z number;
        ans number;

BEGIN
  IF (stddev_value = 0) THEN
  RETURN 1;
  END IF;

  x := (x_value-mean_value)/stddev_value;

  IF cumulative = 1 THEN
    z := abs(x)/SQRT(2);
    t := 1/(1+0.5*z);
    ans := t*exp(-z*z-1.26551223+t*(1.00002368+t*(0.37409196+t*(0.09678418+t*(-0.18628806+t*(0.27886807+t*(-1.13520398+t*(1.48851587+t*(-0.82215223+t*0.17087277)))))))))/2;
    If (x <= 0)
     Then RETURN ans;
     Else return  1-ans;
    End if;
  ELSE

   RETURN 1/(sqrt(2*3.14159265358979)*stddev_value)*Exp(-(Power(x_value-mean_value,2)/(2*Power(stddev_value,2)) ));
  END IF;

END;
/

答案 1 :(得分:0)

这是一个快速的解决方案,我没有尝试获得最大的精度或性能。根据您的要求,您可能需要调整数字格式,精度,计算逻辑等。

create or replace function calc_sn_pdf(x in number) return number
is
 pi      CONSTANT NUMBER := 3.14159265358979;
begin
  return 1/sqrt(2*pi) * exp(-x*x/2);
end;
/

cdf必须近似(因为它是没有简单数学公式的az积分函数),一个可能的近似实现如下。许多其他近似值可以在维基百科上找到。

create or replace function calc_sn_cdf(x in number) return number
is
 b0 CONSTANT NUMBER :=  0.2316419; 
 b1 CONSTANT NUMBER :=  0.319381530;
 b2 CONSTANT NUMBER := -0.356563782; 
 b3 CONSTANT NUMBER :=  1.781477937; 
 b4 CONSTANT NUMBER := -1.821255978; 
 b5 CONSTANT number :=  1.330274429;
 v_t  number;
begin
  --see 26.2.17 at http://people.math.sfu.ca/~cbm/aands/page_932.htm
  --see https://en.wikipedia.org/wiki/Normal_distribution#Numerical_approximations_for_the_normal_CDF
  --Zelen & Severo (1964) approximation
  if x < 0 then
    --this approximation works for x>0, but cdf is symmetric for x=0:
    return 1 - calc_sn_cdf(-x);
  else
    v_t := 1 / (1 + b0*x);
    return 1 - calc_sn_pdf(x)*(b1*v_t + b2*v_t*v_t + b3*v_t*v_t*v_t + b4*v_t*v_t*v_t*v_t + b5*v_t*v_t*v_t*v_t*v_t);
  end if;    
end;
/

顺便说一句,如果你需要花很多时间运行这些函数,打开本机pl / sql编译会很有用。

答案 2 :(得分:0)

--I wrote this function in PL/SQL and it works. I compared results with the NORMDIST 
 --Function in excel and the results match very closely. You will need to pass the  
  --following --parameters to the function.

-- 1. Value of X
-- 2. Value of Mean
-- 3. Value of Standard Deviation

--This function returns the same result  when you pass cumulative=TRUE in excel.


create or replace FUNCTION NORMSDIST(x_value number,mean_value number,stddev_value number)
RETURN NUMBER IS

        x number;
        t number;
        z number;
        ans number;

BEGIN
  IF (stddev_value = 0) THEN
  RETURN 1;
  END IF;

  x := (x_value-mean_value)/stddev_value;

  z := abs(x)/SQRT(2);

  t := 1.0/(1.0+0.5*z);

  ans := t*exp(-z*z-1.26551223+t*(1.00002368+t*(0.37409196+t*(0.09678418+t*(-0.18628806+t*(0.27886807+t*(-1.13520398+t*(1.48851587+t*(-0.82215223+t*0.17087277)))))))))/2.0;

     If (x <= 0)   
     Then RETURN ans;
     Else return  1-ans;
    End if; 

END NORMSDIST;