【问题标题】:How can I stop a For loop in C++ when two conditions are met?满足两个条件时,如何在 C++ 中停止 For 循环?
【发布时间】:2019-03-30 10:41:48
【问题描述】:

一旦满足两个条件,我正试图让我的 for 循环停止运行。 n 柜台没有给我问题。我基本上希望循环在循环开始后一旦totalSum 等于自身(或在自身的一定范围内)就停止运行。 我是编码初学者并且是这个网站的新手,所以我提前道歉。为了代表任何人进行测试,我将完整地包含代码。

我将在此处提供更多信息。我的代码按原样运行,尽管在循环期间,计算的值变得很大,我得到一些东西说naninf。在打印出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 表示 x 发生的事情的示例。 “正弦(1)”

-1 1^63/63! = 0.841471
1 1^65/65! = 0.841471
-1 1^67/67! = -inf

在某一点之后,它给了我。感谢您的宝贵时间。

【问题讨论】:

  • TL;DR - 你知道你可以有一个布尔表达式作为循环中的条件,如for (x = 0; x &lt; 100 &amp;&amp; y != z; ++x)?
  • 感谢您的快速回复。是的,我知道我可以有正确或错误的表达,这是我最初尝试做的。这是for( int n = 0, totalSum = 0; n &lt; 100; ++n; totalSum != totalSum) 但我知道 for 是一个预先测试的循环并且不会运行,因为它已经等于它自己。还有就是写错了,那是我的无知。
  • 你想用什么作为第二个条件?
  • 两者;之间的一切都是你的表达。像这样写:for( int n = 0, totalSum = 0; n &lt; 100 &amp;&amp; totalSum != totalSum; ++n )(编辑:仅供参考:totalSum != totalSum 不会是真的 - 所以修正你的逻辑。但这就是你刚刚要求的,所以我只是在这里跟随你的领导。)
  • 我想使用totalSum作为第二个条件,在错误发生之前停止循环。对于之前的回复,我读错了你的问题。所以不,我不明白这将如何工作,但我会通过查找这些操作数的定义来教育我自己。

标签: c++ math trigonometry taylor-series


【解决方案1】:

您对阶乘函数的使用是有缺陷的 - 它会因一个惊人的小输入而溢出,21!将溢出 64 位有符号整数类型。

您所观察到的是未定义的行为,它表现为以 2 的大幂为模返回,因为即使是非常小的阶乘也是 2 的幂的倍数,所以它为零。

根据 IEEE754,除以零会得到 Inf(如果分子为负,则为 -Inf)。

您可以通过简单地将前一个系数乘以作为迭​​代步骤函数的值来修复您的算法,但请注意,内置三角函数不会使用此方法进行评估,因此此练习纯粹是学术性的。

您的实际问题:您可以有多个条件作为停止条件:使用 && 和 ||很常见。

【讨论】:

  • 我不必实际编写阶乘函数,因为这是我班上其他人的工作。如果您能向我解释那段代码的效果,我将不胜感激。因为我实际上不确定它的缺陷(代码方面)。因为我希望在提交我的工作之前让它正常运行。
【解决方案2】:

如果不仔细查看您的代码,您可能会得到以下内容:

int j = 0;
for(int i = 0; i < 10 && j < 10; i++, j += 2)
{
    std::cout << "i: " << i << " j: " << j << endl;
}

【讨论】:

    【解决方案3】:

    一般来说,有两种方法可以中断任何条件循环。

    1 - 您满足循环不再有效的某些条件:

    while( myConditionIsTrue() ) 
    {
        ...
    }
    

    其中myConditionIsTrue() 是可以评估为非0 或布尔值的任何值。这可以是简单的true 用于无限循环,或x == y 用于简单条件,或者更复杂的x == y &amp;&amp; a != b,甚至是返回某些内容以继续或中断循环的方法调用。

    我向你展示了一个while 循环,但for 循环是一样的,for 实际上是:

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

    2 - 你明确地跳出循环:

    使用关键字break 可让您在任何给定时间中断任何循环,如果遇到意外情况时使用它,因此它不会成为循环的主要条件的一部分,但在您使用时要小心使用它,因为多个退出点会使代码难以理解和阅读。

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

    还有workd continue,它不会中断循环,只是忽略本次迭代的其余循环并跳转到下一次迭代,进入循环的乞求。

    【讨论】:

      【解决方案4】:

      你已经为小的n 溢出了factorial。您应该使用更长的类型,但这不会解决真正的问题。考虑到您在每次迭代中添加的增量实际上是一个很小的数字,并且您可以从上一步中的增量轻松计算出增量:

      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。

      【讨论】:

        【解决方案5】:

        如果我误解了,请纠正我,但如果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)
        

        最后一个可能会让某些人反感。

        【讨论】:

        • 所以“my_epsilon”只是totalSum 的占位符,还是需要用一个值替换。 (int n = 0; n &lt; 100 &amp;&amp; 0.00001 &lt; std::abs(adjust); ++n)?我不确定这里应该使用的格式,或者类似(int n = 0; n &lt; 100 &amp;&amp; totalSum &lt; std::abs(0.00001); ++n)
        • @Kyronsk8 -- 我输入my_epsilon 并假设它是一个命名常量。您可以将其替换为0.00001,如您的评论中所述,或者您可以将其保留在那里,并在循环之外为其赋予一个值:const long double my_epsilon = 0.00001;。通常,后一种方法更可取,因为名称(您可能会选择更好的名称)告诉您其目的是什么,而仅值并不能说明太多。您经常会看到这句话是“不要使用幻数”。
        猜你喜欢
        • 1970-01-01
        • 2022-01-02
        • 2016-04-12
        • 1970-01-01
        • 2022-01-16
        • 1970-01-01
        • 2019-01-29
        • 2013-11-22
        • 1970-01-01
        相关资源
        最近更新 更多