我刚开始学习c++。出于好奇,我创建了一个sine函数,没有使用任何库(除了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〈n+n+1',但如果我试图写'a〈2n+1',它会给我丑陋的编译错误。为什么会这样?我能做些什么来使它这样?
2)如果我尝试输入n的大值(〉15-16),它给出的答案是“nan”。为什么会这样?我认为double具有巨大的存储数字的容量(10^408)。如果我错了,请纠正我。或者可以做些什么来使它计算n的大值。
3)我知道我写的代码很难看,我不想使用任何库函数。无论如何,我可以做些什么来使这段代码在算法方面做得更好。有没有其他有效的方法,而不使用任何库。
4)还有其他的意见/提示/提示,以便将来学习更多?
4条答案
按热度按时间flvlnr441#
1.使用
a < 2*n +1
。1,307,674,368,000
。这个数字不能用int
表示。你必须重新考虑你用来计算sine
的泰勒级数项的代码。1.最好将你的工作代码发布在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
。下面是一个示例程序:
样品输入:
输出:
样品输入:
输出:
样品输入:
输出:
P.S.当N从20变为200时,输出没有变化。
vdgimpew2#
1)你需要写
你可以使用递归函数来使代码更好更清晰。
eaf3rand3#
你将很难说服任何人相信你的说法“完美地工作”,特别是因为你继续描述问题。
1)在C中,
2n+1
不会将n
加倍并将1
添加到它上面。正确的表达式是(大概)2*n + 1
。回去阅读C的任何基本介绍以理解为什么。2)你计算
sin()
的方法将一个值提升到一个很大的幂。如果你将一个值提升到16次幂,它不需要一个特别大的值来溢出大多数浮点表示,即产生一个大于浮点类型所能表示的值。其结果在C中是未定义的,但是对于IEEE表示,结果是NaN
。2a)您忽略的一个问题是
factorial()
增长非常快。(对应于所需的最小值)将在计算8!
时溢出。32位有符号整数(在实践中常见,但不保证)在计算13!
时会溢出。即使是64位有符号int
(在某些编译器中确实存在)在计算21!
时会溢出。(内置)有符号整型是未定义的行为。选择一个较大的整数不会解决这个问题,因为阶乘对于较大的值增长得更快-不是说从32位整数更改为64位整数只会提高计算14
和20
之间的阶乘的能力。3)最大的问题是你期望能够计算大的值(溢出变量),将它们相除,并得到数学上合理的结果。计算机不是这样工作的。并且从你的意识中去除任何需要使用
pow()
或factorial()
的概念-如果这两个溢出,将它们的结果相除是毫无意义的(而且,在你的情况下,两者都可能溢出)。你需要做的是看看泰勒级数中的连续项,并利用它们之间的数学关系。泰勒级数的第一项(当计算
sin(x)
时)是x
。第二个是-x^3/3!
[使用^
表示“的幂”,虽然这不是有效的C]。第三个是+x^5/5!
。第四个是-x^7/7!
。考虑第一个和第二个项之间的关系。然后考虑第二项和第三项之间的关系,将其推广,您将有一种使用泰勒斯级数计算sin()
的方法,大大降低了溢出的风险。而且,如果有人试图告诉你使用“巨大的整数”(一种没有上限的整数类型)和“巨大的浮点类型”,忽略它们。是的,这些东西有它们的位置,但你最好避免使用它们。在这种情况下,避免使用它们是可能的。
yzuktlbb4#
以下是我使用泰勒斯展开的wikipedia示例,我认为这些是最快的。您可以删除包含“t+=...”的最后一行,以获得低精度和高性能: