Как я могу остановить цикл For в C ++, когда выполняются два условия? - PullRequest
0 голосов
/ 25 октября 2018

Я пытаюсь остановить цикл 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

После определенного момента это дает мне это.Спасибо за ваше время.

Ответы [ 5 ]

0 голосов
/ 25 октября 2018

Поправьте меня, если я неправильно понял, но звучит так, как будто вы хотите выйти из цикла, если новое значение 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)

Этот последний, вероятно, неприятен для некоторых людей.

0 голосов
/ 25 октября 2018

Вы страдаете от переполнения 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.

0 голосов
/ 25 октября 2018

Не глядя слишком внимательно на ваш код, вы можете получить что-то вроде:

int j = 0;
for(int i = 0; i < 10 && j < 10; i++, j += 2)
{
    std::cout << "i: " << i << " j: " << j << endl;
}
0 голосов
/ 25 октября 2018

Вообще говоря, существует 2 способа прерывания любого условного цикла.

1 - Вы соответствуете некоторым критериям, когда цикл больше недействителен:

while( myConditionIsTrue() ) 
{
    ...
}

, где myConditionIsTrue() - это что-нибудьэто может быть оценено как не 0 или логическое значение.Это может быть что-то простое, например true для бесконечного цикла, x == y для простого условия, или что-то более сложное, например x == y && a != b, или даже вызов метода, который вернет что-то для продолжения или прерывания цикла.

Я показал вам цикл while, но цикл for точно такой же, где на самом деле for:

for(initializationCode(); myConditionIsTrue(); thisCodeRunsAtTheEndOfEachIteration()) 
{
    ...
}

2 - Вы явно прервались изцикл:

Использование ключевого слова break позволяет вам прервать любой цикл в любой момент времени, используйте его, если вы столкнулись с ситуацией, которая не ожидается, поэтому она не будет частью основного условия вашего цикла, но будьте осторожны при использовании, так как несколько точек выхода могут затруднить отслеживание и чтение кода.

while(x != y) 
{
    if(x < 0) 
    {
        break; // interrupts the while loop.
    }
}

Также есть workd continue, который вместо прерывания цикла просто игнорируетОстальная часть цикла на этой итерации переходит к следующей итерации, переходя к началу цикла.

0 голосов
/ 25 октября 2018

Неправильное использование вами факториальной функции - она ​​будет переполнена при удивительно небольшом входе, 21!переполнит 64-битный целочисленный тип со знаком.

То, что вы наблюдаете, - это неопределенное поведение, которое проявляется как возвращение по модулю большой степени двойки, равной нулю, поскольку даже очень маленький факториал будет кратным степенииз двух.

Это деление на ноль дает вам Inf (-Inf, если числитель отрицателен), в соответствии с IEEE754.

Вы можете исправить свой алгоритм, просто умножив предыдущий коэффициент на значениеэто функция шага итерации, но обратите внимание, что встроенные тригонометрические функции не оцениваются с помощью этого метода, поэтому это упражнение носит чисто академический характер.

Ваш фактический вопрос: вы можете иметь несколько условий в качестве условия остановки:использование && и ||распространено.

...