我是学习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)将来学习更多的其他评论/提示/技巧?
答案 0 :(得分:6)
使用a < 2*n +1
。
阶乘15是1,307,674,368,000
。该号码无法用int
表示。您必须重新考虑用于计算sine
的泰勒级数项的代码。
最好在http://codereview.stackexchange.com发布您的工作代码,以获得有关如何改进代码的反馈。
泰勒级数展开的第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))
使用此逻辑时,您不需要pow
或factorial
。你很容易从第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)最大的问题是你期望能够计算大值(溢出变量),除以它们,并获得数学上理智的结果。计算机不会这样工作。从你的意识中删除任何使用你的14
或20
的概念 - 如果其中任何一个溢出,将它们的结果分开是没有意义的(并且,在你的情况下,两者都可能溢出)。你需要做的是查看泰勒系列中的连续项,并利用它们之间的数学关系。
Taylor系列中的第一个术语(计算pow()
时)是factorial()
。第二个是sin(x)
[使用x
代表&#34;以及#34;的力量,虽然这不是有效的C ++]。第三个是-x^3/3!
。第四个是^
。考虑第一个和第二个术语之间的关系。然后考虑第二和第三项之间的关系。概括一下,您将有一种使用泰勒系列计算+x^5/5!
的方法,可以显着降低溢出事件的风险。
并且,如果有人试图告诉你使用&#34;巨大的整数&#34; (没有上限的整数类型)和#34;巨大的浮点类型&#34;,忽略它们。是的,那些东西都有它们的位置,但如果可以的话,最好不要再需要它们。在这种情况下可以避免这种需要。