私自身の質問に答えて、この問題に遭遇する将来のコーダーのために-私たちはdotPeekを使用してモジュールを逆コンパイルし、次のようになりました:
public static double Rate(double NPer, double Pmt, double PV, double FV = 0.0, DueDate Due = DueDate.EndOfPeriod, double Guess = 0.1)
{
if (NPer <= 0.0)
throw new ArgumentException(Utils.GetResourceString("Rate_NPerMustBeGTZero"));
double Rate1 = Guess;
double num1 = Financial.LEvalRate(Rate1, NPer, Pmt, PV, FV, Due);
double Rate2 = num1 <= 0.0 ? Rate1 * 2.0 : Rate1 / 2.0;
double num2 = Financial.LEvalRate(Rate2, NPer, Pmt, PV, FV, Due);
int num3 = 0;
do
{
if (num2 == num1)
{
if (Rate2 > Rate1)
Rate1 -= 1E-05;
else
Rate1 -= -1E-05;
num1 = Financial.LEvalRate(Rate1, NPer, Pmt, PV, FV, Due);
if (num2 == num1)
throw new ArgumentException(Utils.GetResourceString("Financial_CalcDivByZero"));
}
double Rate3 = Rate2 - (Rate2 - Rate1) * num2 / (num2 - num1);
double num4 = Financial.LEvalRate(Rate3, NPer, Pmt, PV, FV, Due);
if (Math.Abs(num4) < 1E-07)
return Rate3;
double num5 = num4;
num1 = num2;
num2 = num5;
double num6 = Rate3;
Rate1 = Rate2;
Rate2 = num6;
checked { ++num3; }
}
while (num3 <= 39);
throw new ArgumentException(Utils.GetResourceString("Financial_CannotCalculateRate"));
}
private static double LEvalRate(double Rate, double NPer, double Pmt, double PV, double dFv, DueDate Due)
{
if (Rate == 0.0)
return PV + Pmt * NPer + dFv;
double num1 = Math.Pow(Rate + 1.0, NPer);
double num2 = Due == DueDate.EndOfPeriod ? 1.0 : 1.0 + Rate;
return PV * num1 + Pmt * num2 * (num1 - 1.0) / Rate + dFv;
}
num3を超えると、39にハード制限があるため、エラーがスローされることがわかります。コードを少し整理し、制限を100に増やしました。
private static double CalculateUpfrontNominalRate(double numberOfPeriods, double payment, double presentValue, double futureValue = 0.0, DueDate Due = DueDate.EndOfPeriod, double Guess = 0.1)
{
if (numberOfPeriods <= 0.0)
{
throw new ArgumentException("CalculateUpfrontNominalRate: Number of periods must be greater than zero");
}
var rateUpperBoundary = Guess;
var lEvalRate1 = LEvalRate(rateUpperBoundary, numberOfPeriods, payment, presentValue, futureValue, Due);
var rateLowerBoundary = lEvalRate1 <= 0.0 ? rateUpperBoundary * 2.0 : rateUpperBoundary / 2.0;
var lEvalRate2 = LEvalRate(rateLowerBoundary, numberOfPeriods, payment, presentValue, futureValue, Due);
for (var i = 0; i < 100; i++)
{
if (lEvalRate2 == lEvalRate1)
{
if (rateLowerBoundary > rateUpperBoundary)
rateUpperBoundary -= 1E-05;
else
rateUpperBoundary -= -1E-05;
lEvalRate1 = LEvalRate(rateUpperBoundary, numberOfPeriods, payment, presentValue, futureValue, Due);
if (lEvalRate2 == lEvalRate1)
{
throw new ArgumentException("CalculateUpfrontNominalRate: Inputs will cause a divsion by zero");
}
}
double temporaryRate = rateLowerBoundary - (rateLowerBoundary - rateUpperBoundary) * lEvalRate2 / (lEvalRate2 - lEvalRate1);
double lEvalRate3 = LEvalRate(temporaryRate, numberOfPeriods, payment, presentValue, futureValue, Due);
if (Math.Abs(lEvalRate3) < 1E-07)
{
return temporaryRate;
}
lEvalRate1 = lEvalRate2;
lEvalRate2 = lEvalRate3;
rateUpperBoundary = rateLowerBoundary;
rateLowerBoundary = temporaryRate;
}
throw new ArgumentException("CalculateUpfrontNominalRate: The maximum number of iterations has been exceeded, unable to calculate rate");
}
private static double LEvalRate(double Rate, double NPer, double Pmt, double PV, double dFv, DueDate Due)
{
if (Rate == 0.0)
return PV + Pmt * NPer + dFv;
double num1 = Math.Pow(Rate + 1.0, NPer);
double num2 = Due == DueDate.EndOfPeriod ? 1.0 : 1.0 + Rate;
return PV * num1 + Pmt * num2 * (num1 - 1.0) / Rate + dFv;
}