简体   繁体   English

没有任何库的正弦函数

[英]Sine Function without any library

I am new at learning c++. 我是学习c ++的新手。 Because of curiosity, I created a sine function without using any library (except iostream, to take input and output). 由于好奇心,我创建了一个不使用任何库的正弦函数(iostream除外,用于输入和输出)。 Here is the code that I wrote, and it works perfectly. 这是我编写的代码,它可以完美运行。

    #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;
}

It uses taylor series to calculate sine. 它使用泰勒级数来计算正弦。 I also takes 'n' as number of terms to include from taylor series to improve accuracy. 我也将'n'作为包含在taylor系列中的术语数以提高准确性。 I have certain doubts in this 我对此有些怀疑

1) the sin function i created, I found by trial and error that in the for loop, I have to write 'a< n+n+1' , but If I tried to write 'a<2n+1' it gives me ugly compilation error. 1)我创建的sin函数通过反复试验发现,在for循环中,我必须写'a <n + n + 1',但是如果我尝试写'a <2n + 1',它将给我丑陋的编译错误。 Why is it so? 为什么会这样呢? What can I do to make it that way? 我该怎么做才能做到这一点?

2)If I try to enter large values of n (>15-16) it gives answer as 'nan'. 2)如果我尝试输入较大的n(> 15-16),则答案为“ nan”。 Why is it so? 为什么会这样呢? I think double has huge capacity of storing numbers (10^408). 我认为double具有存储数字的巨大容量(10 ^ 408)。 Correct me If I'm wrong. 如果我错了纠正我。 Or what can be done to make it calculate for huge value of n. 或者可以做些什么使它计算出巨大的n值。

3) I know the code I written is ugly, I don't want to use any library functions. 3)我知道我编写的代码很丑陋,我不想使用任何库函数。 Anyway what can I do to make this code do better in terms of algorithm. 无论如何,我该怎么做才能使此代码在算法方面做得更好。 Is there any other efficient way without using any library. 有没有使用任何库的任何其他有效方法。

4) Any other comments/hints/tips for learning more in future? 4)还有其他意见/提示/技巧,供以后学习使用?

  1. Use a < 2*n +1 . 使用a < 2*n +1

  2. factorial of 15 is 1,307,674,368,000 . 15的阶乘为1,307,674,368,000 That number cannot be represented by an int . 该数字不能用int表示。 You have to rethink the code you use to compute the terms of the Taylor series for sine . 您必须重新考虑用于计算sine泰勒级数项的代码。

  3. It will be better to post your working code at http://codereview.stackexchange.com to get feedback on how to improve your code. 最好将您的工作代码发布在http://codereview.stackexchange.com上,以获取有关如何改进代码的反馈。

N-th term in the Taylor series expansion is (-1)^(N-1)x^(2*N+1)/(2*N+1)! 泰勒级数展开式中的第N个项是(-1)^(N-1)x^(2*N+1)/(2*N+1)!
(N+1)-th term is (-1)^(N)x^(2*(N+1)+1)/(2*(N+1)+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))

When you use this logic, you don't need to need pow or factorial . 使用此逻辑时,不需要powfactorial You derive the (N+t)-th term from the N-th term very easily. 您可以很容易地从第N个项导出第(N + t)个项。 The starting point, T(0) is simply x . 起点T(0)只是x

Here's an example program: 这是一个示例程序:

#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;
}

Sample input: 输入样例:

3.5
5

Output: 输出:

sine of given x equals -0.32838899588879211233

Sample input: 输入样例:

3.5
20

Output: 输出:

sine of given x equals -0.35078322768961955891

Sample input: 输入样例:

3.5
200

Output: 输出:

sine of given x equals -0.35078322768961955891

PS There is no change in output when N is changed from 20 to 200. PS当N从20更改为200时,输出不变。

1) You need to write 1)你需要写

 a < 2*n+1 

You can use recursion functions to do the code more nice and clear. 您可以使用递归函数使代码更清晰。

You would be hard pressed to convince anyone of your claim it "works perfectly", particularly since you go on to describe problems. 您将很难说服任何人说它“完美”,特别是因为您继续描述问题。

1) is a basic misunderstanding on your part with expressions. 1)是您对表达式的基本误解。 2n+1 does not double n and add 1 to it, in C++. 在C ++中, 2n+1不会将n加倍,也不会加1 The correct expression is (presumably) 2*n + 1 . 正确的表达式是(大概) 2*n + 1 Go back and read any elementary introduction to C++ to understand why. 返回并阅读有关C ++的任何基本介绍,以了解其原因。

2) Your method of computing sin() raises a value to a large power. 2)您计算sin()将一个值提高为大幂。 If you're raising a value to the 16th power, it doesn't take a particularly large value to overflow most floating point representations ie produce a value larger than the floating point type can represent. 如果您将值提高到16的幂,则不需要花费特别大的值就可以使大多数浮点表示形式溢出,即产生一个大于浮点类型可以表示的值。 The result of that is undefined in C++, but with IEEE representations the result is a NaN . 其结果在C ++中未定义,但使用IEEE表示,结果为NaN

2a) A problem you have missed is that factorial() grows very fast. 2a)您错过的一个问题是factorial()增长非常快。 A 16-bit signed int (which corresponds to the minimum required) will overflow when calculating 8! 计算8!时,将溢出一个16位有符号int (对应于所需的最小值) 8! . A 32 bit signed integer (common in practice, but not guaranteed) will overflow when computing 13! 计算13!时,32位有符号整数(实际上是常见的,但不能保证)将溢出13! . Even a 64-bit signed int (which does exist with some compilers) will overflow when calculating 21! 计算21!时,即使是64位带符号的int (某些编译器中也确实存在)都将溢出21! . The result of overflowing a (built-in) signed integral type is undefined behaviour. (内置)带符号整数类型溢出的结果是未定义的行为。 Picking a larger sized integer won't address this, since factorial grows faster for larger values - not that changing from a 32-bit integer to a 64-bit integer only improves ability to calculate factorials between 14 and 20 . 选择一个较大的整数将无法解决这个问题,因为阶乘对于较大的值会更快增长-从32位整数更改为64位整数不会提高在1420之间计算阶乘的能力。

3) The big problem is that you are expecting to be able to compute big values (which overflow variables), divide them, and get a mathematically sane result. 3)最大的问题是您期望能够计算大值(溢出变量),将它们除以并获得数学上合理的结果。 Computers don't work that way. 电脑不能那样工作。 And remove from your consciousness any concept that using your pow() or factorial() is required - if either of those overflow, dividing their results is pointless (and, in your case, both probably are overflowing). 并从您的意识中删除需要使用pow()factorial()任何概念-如果这两个溢出中的任何一个溢出,将它们的结果除以是没有意义的(并且,在您的情况下,可能都在溢出)。 What you need to do is look at the consecutive terms in the Taylor series, and exploit mathematical relationships between them. 您需要做的是查看泰勒级数中的连续项,并利用它们之间的数学关系。

The first term in the Taylor's series (when computing sin(x) ) is x . 泰勒级数(计算sin(x) )的第一项是x The second is -x^3/3! 第二个是-x^3/3! [using ^ to represent "to the power of", although that is not valid C++]. [使用^表示“至”的力量,尽管这不是有效的C ++)。 The third is +x^5/5! 第三个是+x^5/5! . The fourth is -x^7/7! 第四个是-x^7/7! . Consider what the relationship is between the first and second terms. 考虑一下第一项和第二项之间的关系。 Then consider what the relationship is between the second and third terms. 然后考虑第二项和第三项之间的关系。 Generalise that, and you will have a method to compute sin() using the Taylors series with significantly reduced risk of overflowing something. 概括一下,您将拥有使用Taylors级数来计算sin()方法,大大降低了发生溢出的风险。

And, if anyone tried to tell you to use a "huge integer" (an integral type that has no upper bound) and a "huge floating point type", ignore them. 并且,如果有人试图告诉您使用“巨大整数”(没有上限的整数类型)和“巨大浮点类型”,请忽略它们。 Yes, those things have their place, but you are better off avoiding the need for them if you can. 是的,这些东西都有它们的位置,但是如果可以的话,最好避免使用它们。 It is possible to avoid that need in this case. 在这种情况下可以避免这种需要。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM