Вы можете немного упростить это.Но сначала, что не так с вашим существующим кодом, так это то, что вы неправильно вычисляете i!
.Последовательность, которую вы на самом деле вычисляете сейчас:
X^N / N + X^N / (2 * N) + X^N / (3 * N) + ... + X^N / ((N - 1) * N)
Несколько вещей: - Цикл имеет проблему с одним смещением - Числитель возведен в неверную степень- Знаменатель этих должен быть i!
Факториалы определяются через простое рекуррентное соотношение:
i! = i * (i - 1)!
и 0! = 1
Или, другими словами, произведение первых i
последовательных натуральных чисел.Поэтому один из способов исправить это - создать метод с именем Factorial:
static long Factorial(int i)
{
long product = 1;
while (i > 0) {
product *= i;
--i;
}
return product;
}
Затем вы можете исправить свой цикл следующим образом:
for (int i = 1; i < N; i++)
{
sum += Math.Pow(X, i) / Factorial(i);
}
Однако мы переделываем многоработать каждую итерацию цикла, что нам не нужно делать.Вот тут-то и наступает упрощение. Общая формула для i
'-го термина такова:
C[i] = X^i / i!
Но мы можем также написать это в терминах термина, который пришелперед этим:
C[i] = C[i-1] * X / i
Таким образом, мы можем переписать цикл следующим образом:
double lastTerm = 1;
for (int i = 1; i <= N; ++i)
{
// Cast to double here or, probably better, make X a double in the first place.
lastTerm *= (double) X / i;
sum += lastTerm;
}
Это имеет несколько преимуществ:
- Как правило, это будет быстрее, поскольку мы выполняем меньше работы на каждой итерации (
Math.Pow
вычисляет произвольные степени, поэтому это немного медленнее, чем просто умножение). - Это будет менее подвержено численным проблемам.Факториалы становятся действительно большими очень быстро.На самом деле 21!уже слишком велик для хранения в
long
, поэтому, если ваш N
больше этого, все сломается.