没有任何库的正弦函数

时间:2016-01-10 07:32:03

标签: c++ c++11

我是学习c ++的新手。由于好奇心,我创建了一个正弦函数而不使用任何库(iostream除外,用于输入和输出)。这是我写的代码,它完美无缺。

    #include<iostream>
using namespace std;
int factorial(int n);
double sin(double x, int n);
double pow(double x, int n);
int main(){
    double num;
    int n;
    cout << "Enter any Number" << endl;
    cin >> num;
    cout << "Enter n" <<  endl;
    cin >> n;
    cout << "sine of given x equals " << sin(num, n);
}
int factorial(int n){
    int a=1;
    for(int p=1; p<=n; p++){
        a=a*p;
    }
        return a;
}
double sin(double x, int n){
    double sine=0;
    for ( int a=1, b=1; a<n+n+1; a+=2, b++){
        sine=sine + (pow(-1, b+1))*(pow(x,a))/(factorial(a));
    }
    return sine;
}
double pow(double x, int n){
    double num=1;
    for (int a=1; a<=n; a++){
        num=num*x;
    }
    return num;
}

它使用泰勒系列计算正弦。我还将'n'作为术语数量包含在泰勒系列中以提高准确性。我对此有一些疑问

1)我创建的sin函数,我通过反复试验发现在for循环中,我必须写'a&lt; n + n + 1',但如果我试图写'a&lt; 2n + 1',它会给我带来丑陋的编译错误。为什么会这样?我能做些什么来做到这一点?

2)如果我尝试输入大的n值(> 15-16),则给出答案为'nan'。为什么会这样?我认为double具有巨大的存储数量(10 ^ 408)。如我错了请纠正我。或者可以做些什么来计算n的巨大价值。

3)我知道我写的代码很难看,我不想使用任何库函数。无论如何,我可以做些什么来使这个代码在算法方面做得更好。没有使用任何库,有没有其他有效的方法。

4)将来学习更多的其他评论/提示/技巧?

3 个答案:

答案 0 :(得分:6)

  1. 使用a < 2*n +1

  2. 阶乘15是1,307,674,368,000。该号码无法用int表示。您必须重新考虑用于计算sine的泰勒级数项的代码。

  3. 最好在http://codereview.stackexchange.com发布您的工作代码,以获得有关如何改进代码的反馈。

  4. 泰勒级数展开的第N个项是(-1)^(N-1)x^(2*N+1)/(2*N+1)!
    (N + 1)项是(-1)^(N)x^(2*(N+1)+1)/(2*(N+1)+1)!

    T(N+1) = -1*T(N)*x^2/((2*(N+1)+1)*(2*(N+1))

    使用此逻辑时,您不需要powfactorial。你很容易从第N个项中推导出第(N + t)项。起点T(0)只是x

    这是一个示例程序:

    #include <iostream>
    #include <iomanip>
    
    using namespace std;
    
    double sin(double x, int n)
    {
       double t = x;
       double sine = t;
       for ( int a=1; a<n; ++a)
       {
          double mult = -x*x/((2*a+1)*(2*a));
          t *= mult;
          sine += t;
       }
       return sine;
    }
    
    int main()
    {
        double num;
        int n;
        cout << "Enter any Number" << endl;
        cin >> num;
        cout << "Enter n" <<  endl;
        cin >> n;
        cout << std::setprecision(20) << "sine of given x equals " << sin(num, n) << std::endl;
    
       return 0;
    }
    

    示例输入:

    3.5
    5
    

    输出:

    sine of given x equals -0.32838899588879211233
    

    示例输入:

    3.5
    20
    

    输出:

    sine of given x equals -0.35078322768961955891
    

    示例输入:

    3.5
    200
    

    输出:

    sine of given x equals -0.35078322768961955891
    

    P.S。当N从20变为200时,输出没有变化。

答案 1 :(得分:3)

1)你需要写

 a < 2*n+1 

您可以使用递归函数来使代码更加清晰。

答案 2 :(得分:3)

你很难说服你的任何人声称它能够完美地运作,特别是在你继续描述问题之后。

1)是你表达方式的基本误解。在{+ C ++}中,(1,3,h,w)不会加倍2n+1并向其添加n。正确的表达式(推测)1。回过头来阅读C ++的任何基本介绍,了解原因。

2)你的计算方法2*n + 1将一个值提升到一个大的权力。如果你将值提高到16次幂,它就不会采用特别大的值来溢出大多数浮点表示,即产生大于浮点类型可以表示的值。其结果在C ++中未定义,但在IEEE表示中,结果为sin()

2a)你错过的一个问题是NaN增长得非常快。计算factorial()时,16位带符号int(对应于所需的最小值)将溢出。在计算8!时,32位有符号整数(在实践中很常见,但不能保证)会溢出。在计算13!时,即使是64位带符号int(某些编译器也存在)也会溢出。溢出(内置)有符号整数类型的结果是未定义的行为。选择一个较大的整数不会解决这个问题,因为对于较大的值,因子增长得更快 - 而不是从32位整数变为64位整数只能提高计算21!和{之间的因子的能力。 {1}}。

3)最大的问题是你期望能够计算大值(溢出变量),除以它们,并获得数学上理智的结果。计算机不会这样工作。从你的意识中删除任何使用你的1420的概念 - 如果其中任何一个溢出,将它们的结果分开是没有意义的(并且,在你的情况下,两者都可能溢出)。你需要做的是查看泰勒系列中的连续项,并利用它们之间的数学关系。

Taylor系列中的第一个术语(计算pow()时)是factorial()。第二个是sin(x) [使用x代表&#34;以及#34;的力量,虽然这不是有效的C ++]。第三个是-x^3/3!。第四个是^。考虑第一个和第二个术语之间的关系。然后考虑第二和第三项之间的关系。概括一下,您将有一种使用泰勒系列计算+x^5/5!的方法,可以显着降低溢出事件的风险。

并且,如果有人试图告诉你使用&#34;巨大的整数&#34; (没有上限的整数类型)和#34;巨大的浮点类型&#34;,忽略它们。是的,那些东西都有它们的位置,但如果可以的话,最好不要再需要它们。在这种情况下可以避免这种需要。