Я пытаюсь заставить мой цикл for перестать работать, как только будут выполнены два условия. n
Счетчик не дает мне проблемы. Я бы хотел, чтобы цикл перестал работать totalSum
равен самому себе (или в пределах определенной границы) после запуска цикла. Я новичок в программировании и новичок в этом сайте, поэтому заранее прошу прощения. для тестирования от имени кого-либо, я включу код в полном объеме.
Я предоставлю больше информации здесь. мой код работает как надо, хотя во время цикла вычисляемые значения становятся слишком большими, и я получаю что-то, говорящее nan
или же inf
, после распечатки totalSum
и тому подобное. Я вижу, что получаю значение (правильное вычисление синуса), повторенное один или два раза, но после этого число продолжает увеличиваться или уменьшаться циклом. Как только мой цикл окончательно заканчивается через 100 раз, я получаю вышеупомянутое nan
/inf
,
long double sine(double x)
{
long double totalSum = 0.0;
for(int n = 0; n < 100; ++n)
{
int plusOrMinusSign = pow(-1, n);
long double num = pow(x,(2 * n + 1));
long double den = factorialtest(2 * n + 1);
totalSum += (plusOrMinusSign * num / den);
cout <<plusOrMinusSign<<" "<< x << "^" <<(2*n+1) <<"/"<< (2 * n + 1)<<"! = " << totalSum <<endl; //testing purposes
}
return totalSum;
}
Вся программа ниже
#include <iostream>
#include <cmath> //used for pow indicated in comment with "^"#include <iomanip>
using namespace std;
long int factorialtest(int x) //calculates factorial
{
long int factorialNum = 1;
for(int count = 1; count <= x; count++)
factorialNum = factorialNum * count;
return factorialNum;
}
long double sine(double x)
{
long double totalSum = 0.0;
for(int n = 0; n < 100; ++n)
{
int plusOrMinusSign = pow(-1, n);
long double num = pow(x,(2 * n + 1));
long double den = factorialtest(2 * n + 1);
totalSum += (plusOrMinusSign * num / den);
cout <<plusOrMinusSign<<" "<< x << "^" <<(2*n+1) <<"/"<< (2 * n + 1)<<"! = " << totalSum <<endl; //testing purposes
}
return totalSum;
}
double cosine(double x) //returns cos of x
{
double totalSum = 0;
for(int n = 0; n < 100; n = n + 2)
{
double num = pow(x,(n)); // ^ used pow here, does the power of x to the n value above
double den = factorialtest(n); //used my own factorial program here, multiplies n by factorial of n
totalSum = totalSum + ( num / den);
}
return totalSum = 0;
}
double tangent(double x) { //returns tangent
return sine(x) / cosine(x);
}
double secant(double x) { //returns secant
return 1 / cosine(x);
}
double cosecant(double x) { //returns cosecant
return 1 / sine(x);
}
double cotangent(double x) { //returns cotangent
return 1 / tangent(x);
}
int main() {
double x;
cout << "Input number to find sine: ";
cin >> x;
cout << "Sine of " << x << " is " << sine(x) << endl;}
Программа расчета радиан между прочим. Пример того, что происходит ниже, используя 1 для х. «Синус (1)»
-1 1^63/63! = 0.841471
1 1^65/65! = 0.841471
-1 1^67/67! = -inf
После определенного момента это дает мне это. Спасибо за ваше время.
Неправильное использование вами факториальной функции — она будет переполнена при удивительно небольшом входе, 21! переполнит 64-битный целочисленный тип со знаком.
То, что вы наблюдаете, — это неопределенное поведение, которое проявляется как возвращение по модулю большой степени двойки, которая равна нулю, поскольку даже очень маленький факториал будет кратен степени двух.
Это деление на ноль дает вам Inf (-Inf, если числитель отрицателен), в соответствии с IEEE754.
Вы можете исправить свой алгоритм, просто умножив предыдущий коэффициент на значение, являющееся функцией шага итерации, но обратите внимание, что встроенные тригонометрические функции не оцениваются с помощью этого метода, поэтому данное упражнение носит чисто академический характер.
Ваш актуальный вопрос: у вас может быть несколько условий в качестве условия остановки: использование && и || распространено
Не глядя слишком внимательно на ваш код, вы можете получить что-то вроде:
int j = 0;
for(int i = 0; i < 10 && j < 10; i++, j += 2)
{
std::cout << "i: " << i << " j: " << j << endl;
}
Вообще говоря, существует 2 способа прерывания любого условного цикла.
while( myConditionIsTrue() )
{
...
}
где myConditionIsTrue()
это все, что может быть оценено как не 0 или логическое значение. Это может быть что-то так просто, как true
для бесконечного цикла, или x == y
для простого условия, или что-то более сложное, как x == y && a != b
или даже вызов метода, который вернет что-то, чтобы продолжить или разорвать цикл.
Я показал вам while
петля, но for
петля точно такая же, где for
на самом деле:
for(initializationCode(); myConditionIsTrue(); thisCodeRunsAtTheEndOfEachIteration())
{
...
}
Используя ключевое слово break
позволяет вам прервать любой цикл в любой момент времени, используйте его, если вы столкнулись с непредвиденной ситуацией, поэтому он не будет частью основного условия вашего цикла, но будьте осторожны при его использовании, так как несколько точек выхода могут сделать код трудно следовать и читать.
while(x != y)
{
if(x < 0)
{
break; // interrupts the while loop.
}
}
Также есть работа continue
, который вместо прерывания цикла просто игнорирует остальную часть цикла на этой итерации и переходит к следующей итерации, переходя к началу цикла.
Вы страдаете от factorial
переполнен уже для маленьких n
, Вы должны использовать более длинный тип, но это не решит реальную проблему. Учтите, что приращение, которое вы добавляете в каждой итерации, на самом деле является небольшим числом, и что вы можете легко вычислить приращение по сравнению с предыдущим шагом:
double increment = 1;
for(int n = 0; n < 100; ++n) {
int plusOrMinusSign = n % 2;
totalSum += (plusOrMinusSign * increment);
increment *= x; // exponential part
increment /= (n+1); // factorial part
}
Я не удосужился дать правильную математику, но я надеюсь, что вы поняли идею. x
является фиксированным и n
растет только линейно, поэтому существует небольшая опасность переполнения (особенно, как вы ожидаете increment
сходиться к 0
).
Я не получил то, что вы хотите использовать в качестве второго условия. Однако, ради полноты: допустим, что условия A и B, тогда вы прерываете цикл через:
for (int i; A && B; ++i) { }
или же
for (int i; ; ++i) {
if (A && B) break;
}
есть, по крайней мере, третий способ, но чтобы не начинать обсуждение, я оставляю заинтересованному читателю вопрос: P.
Поправьте меня, если я неправильно понял, но похоже, что вы хотите выйти из цикла, если новое значение totalSum
близко к старому значению. Это означает, что вы должны быть в состоянии увидеть разницу между новым значением и старым значением. В этом случае это просто: разница между ними просто plusOrMinusSign * num / den
, Так что сохраните это как именованную переменную и протестируйте в верхней части цикла:
long double adjust = 10000; // large enough that it won't quit on entry
for (int n = 0; n < 100 && my_epsilon < std::abs(adjust); ++n) {
int plusOrMinusSign = pow(-1, n);
long double num = pow(x,(2 * n + 1));
long double den = factorialtest(2 * n + 1);
adjust = plusOrMinusSign * num / den;
totalSum += adjust;
cout <<plusOrMinusSign<<" "<< x << "^" <<(2*n+1) <<"/"<< (2 * n + 1)<<"! = " << totalSum <<endl; //testing purposes
}
Вы должны решить, какова стоимость my_epsilon
должно быть; это определяет, насколько малой должна быть разница для выхода из цикла.
И пока я здесь, int plusOrMinusSign = pow(-1, n)
не хороший способ переключить знак; это возведение будет медленным. Вместо этого инициализируйте это значение перед циклом:
int plusOrMinusSign = 1;
и затем, в конце тела цикла, просто переключите его:
plusOrMinusSign *= -1;
или поместите это изменение в приращение цикла:
for (int n = 0; n < 100 && my_epsilon < std::abs(adjust); ++n, plusOrMinusSign *= -1)
Этот последний, вероятно, неприятен для некоторых людей.