/// <summary> /// Returns NormalCdfMomentRatio(i,x) for i=n,n+1,n+2,... /// </summary> /// <param name="n">A starting index >= 0</param> /// <param name="x">A real number</param> /// <param name="useConFrac">If true, do not use the lookup table</param> /// <returns></returns> private static IEnumerator <double> NormalCdfMomentRatioSequence(int n, double x, bool useConFrac = false) { if (n < 0) { throw new ArgumentException("n < 0"); } if (x > -1) { // Use the upward recurrence. double rPrev = MMath.NormalCdfRatio(x); if (n == 0) { yield return(rPrev); } double r = x * rPrev + 1; if (n <= 1) { yield return(r); } for (int i = 1; ; i++) { double rNew = (x * r + rPrev) / (i + 1); rPrev = r; r = rNew; if (n <= i + 1) { yield return(r); } } } else { // Use the downward recurrence. // Each batch of tableSize items is generated in advance. // If tableSize is larger than 50, the results will lose accuracy. // If tableSize is too small, then the recurrence is used less often, requiring more computation. int maxTableSize = 30; // rtable[tableStart-i] = R_i double[] rtable = new double[maxTableSize]; int tableStart = -1; int tableSize = 2; for (int i = n; ; i++) { if (i > tableStart) { // build the table tableStart = i + tableSize - 1; if (useConFrac) { rtable[0] = MMath.NormalCdfMomentRatioConFrac(tableStart, x); rtable[1] = MMath.NormalCdfMomentRatioConFrac(tableStart - 1, x); } else { rtable[0] = MMath.NormalCdfMomentRatio(tableStart, x); rtable[1] = MMath.NormalCdfMomentRatio(tableStart - 1, x); } for (int j = 2; j < tableSize; j++) { int nj = tableStart - j + 1; if (rtable[j - 2] == 0 && rtable[j - 1] == 0) { rtable[j] = MMath.NormalCdfMomentRatio(nj - 1, x); } else { rtable[j] = (nj + 1) * rtable[j - 2] - x * rtable[j - 1]; } } // Increase tableSize up to the maximum. tableSize = Math.Min(maxTableSize, 2 * tableSize); } yield return(rtable[tableStart - i]); } } }