コード例 #1
0
 /// <summary>
 /// Get the mean and variance after truncation.
 /// </summary>
 /// <param name="mean"></param>
 /// <param name="variance"></param>
 public void GetMeanAndVariance(out double mean, out double variance)
 {
     if (this.Gamma.IsPointMass)
     {
         mean     = this.Gamma.Point;
         variance = 0.0;
     }
     else if (!IsProper())
     {
         throw new ImproperDistributionException(this);
     }
     else
     {
         // Apply the recurrence GammaUpper(s+1,x,false) = s*GammaUpper(s,x,false) + x^s*exp(-x)
         // Z = GammaUpper(s,r*l,false) - GammaUpper(s,r*u,false)
         // E[x] = (GammaUpper(s+1,r*l,false) - GammaUpper(s+1,r*u,false))/r/Z
         //      = (s + ((r*l)^s*exp(-r*l) - (r*u)^s*exp(-r*u))/Z)/r
         double rl = this.Gamma.Rate * LowerBound;
         double ru = this.Gamma.Rate * UpperBound;
         double m = this.Gamma.Shape / this.Gamma.Rate;
         double offset, offset2;
         if (ru > double.MaxValue)
         {
             double logZ = GetLogNormalizer();
             if (logZ < double.MinValue)
             {
                 mean     = GetMode();
                 variance = 0.0;
                 return;
             }
             offset  = Math.Exp(MMath.GammaUpperLogScale(this.Gamma.Shape, rl) - logZ);
             offset2 = (rl - this.Gamma.Shape) / this.Gamma.Rate * offset;
         }
         else
         {
             // This fails when GammaUpperScale underflows to 0
             double Z = GetNormalizer();
             if (Z == 0)
             {
                 mean     = GetMode();
                 variance = 0.0;
                 return;
             }
             double gammaUpperScaleLower = MMath.GammaUpperScale(this.Gamma.Shape, rl);
             double gammaUpperScaleUpper = MMath.GammaUpperScale(this.Gamma.Shape, ru);
             offset  = (gammaUpperScaleLower - gammaUpperScaleUpper) / Z;
             offset2 = ((rl - this.Gamma.Shape) / this.Gamma.Rate * gammaUpperScaleLower - (ru - this.Gamma.Shape) / this.Gamma.Rate * gammaUpperScaleUpper) / Z;
         }
         if (rl == this.Gamma.Shape)
         {
             mean = LowerBound + offset / this.Gamma.Rate;
         }
         else
         {
             mean = (this.Gamma.Shape + offset) / this.Gamma.Rate;
             if (mean < LowerBound)
             {
                 mean = MMath.NextDouble(mean);
             }
             if (mean < LowerBound)
             {
                 mean = MMath.NextDouble(mean);
             }
         }
         if (mean > double.MaxValue)
         {
             variance = mean;
         }
         else
         {
             variance = (m + offset2 + (1 - offset) * offset / this.Gamma.Rate) / this.Gamma.Rate;
         }
     }
 }