计算三角函数精度下降,误差百分比上升
Computational Trigonometry functions precision decreasing and error percent rising
你好,我正在用 Taylor Series Expansions
求解 sin(x) 和 cos(x) 等三角函数
问题:我的值并没有错,只是不够精确
我的问题是我是否可以提高这些功能的准确性,我想我已经尝试了一切但我需要你的建议。
double trig::funcsin(int value)
{
sum = 0;
//summation
factorial fac;
for(int i = 0; i < 7; i++)
{
sum += pow((-1), i)*(((double)pow(value, (double)2*i+1)/(double)fac.fact((double)2*i+ 1)));
}
return sum;
}
double trig::funccos(int value)
{
factorial fac;
sum = 0;
for(int i = 0;i < 7;i++)
{
sum += (pow((-1), i)*((double)pow(value, (double)2*i)/(double)fac.fact((double)2*i)));
}
return sum;
}
示例:
实数:-0.7568024953
我的:-0.73207
实数:-0.27941549819
我的:-0.501801
随着 x 变大,输出值以指数速率变得不那么精确。
我是GCC编译器,请多多指教
以下代码演示了 sin() 函数的泰勒级数(关于 x==0)。
如您所知,正弦函数每 2*pi 间隔重复一个相同的循环。
但是泰勒级数只是一个多项式——它需要很多项来近似像正弦这样的摆动函数。并且试图在远离原点的某个点逼近正弦函数将需要如此多的项,以至于累积的误差将给出不令人满意的结果。
为了避免这个问题,我的函数首先将 x 重新映射到以零为中心、介于 -pi 和 +pi 之间的单个循环范围。
最好避免使用 pow 和阶乘函数,如果您可以在求和的每个步骤中廉价地更新组件的话。例如,我为 pow(x, 2*n+1) 保留一个 运行 值:它开始设置为 x(在 n==0),然后每次 n 递增时,我将其乘以 x *X。因此,在每一步更新这个值只需要一次乘法。阶乘项也使用了类似的优化。
这个系列在正项和负项之间交替,所以为了避免跟踪我们是否需要添加或减去一个项的麻烦,循环在每次迭代中处理两个项——它添加第一个并减去第二个第二.
每次计算新的总和时,都会将其与之前的总和进行比较。如果两者相等(说明更新已经超过了sum变量的精度),函数returns。这不是测试终止条件的好方法,但它使函数更简单。
#include <iostream>
#include <iomanip>
double mod_pi(double x) {
static const double two_pi = 3.14159265358979 * 2;
const int q = static_cast<int>(x / two_pi + 0.5);
return x - two_pi * q;
}
double func_sin(double x) {
x = mod_pi(x);
double sum = 0;
double a = 1; // 2*n+1 [1, 3, 5, 7, ...]
double b = x; // x^a
double c = 1; // (2*n+1)!
const double x_sq = x * x;
for(;;) {
const double tp = b / c;
// update for negative term
c *= (a+1) * (a+2);
a += 2;
b *= x_sq;
const double tn = b / c;
const double ns = tp - tn + sum;
if(ns == sum) return ns;
sum = ns;
// update for positive term (at top of loop)
c *= (a+1) * (a+2);
a += 2;
b *= x_sq;
}
}
int main() {
const double y = func_sin(-0.858407346398077);
std::cout << std::setprecision(13) << y << std::endl;
}
你好,我正在用 Taylor Series Expansions
求解 sin(x) 和 cos(x) 等三角函数问题:我的值并没有错,只是不够精确
我的问题是我是否可以提高这些功能的准确性,我想我已经尝试了一切但我需要你的建议。
double trig::funcsin(int value)
{
sum = 0;
//summation
factorial fac;
for(int i = 0; i < 7; i++)
{
sum += pow((-1), i)*(((double)pow(value, (double)2*i+1)/(double)fac.fact((double)2*i+ 1)));
}
return sum;
}
double trig::funccos(int value)
{
factorial fac;
sum = 0;
for(int i = 0;i < 7;i++)
{
sum += (pow((-1), i)*((double)pow(value, (double)2*i)/(double)fac.fact((double)2*i)));
}
return sum;
}
示例:
实数:-0.7568024953
我的:-0.73207
实数:-0.27941549819
我的:-0.501801
随着 x 变大,输出值以指数速率变得不那么精确。
我是GCC编译器,请多多指教
以下代码演示了 sin() 函数的泰勒级数(关于 x==0)。 如您所知,正弦函数每 2*pi 间隔重复一个相同的循环。 但是泰勒级数只是一个多项式——它需要很多项来近似像正弦这样的摆动函数。并且试图在远离原点的某个点逼近正弦函数将需要如此多的项,以至于累积的误差将给出不令人满意的结果。
为了避免这个问题,我的函数首先将 x 重新映射到以零为中心、介于 -pi 和 +pi 之间的单个循环范围。
最好避免使用 pow 和阶乘函数,如果您可以在求和的每个步骤中廉价地更新组件的话。例如,我为 pow(x, 2*n+1) 保留一个 运行 值:它开始设置为 x(在 n==0),然后每次 n 递增时,我将其乘以 x *X。因此,在每一步更新这个值只需要一次乘法。阶乘项也使用了类似的优化。
这个系列在正项和负项之间交替,所以为了避免跟踪我们是否需要添加或减去一个项的麻烦,循环在每次迭代中处理两个项——它添加第一个并减去第二个第二.
每次计算新的总和时,都会将其与之前的总和进行比较。如果两者相等(说明更新已经超过了sum变量的精度),函数returns。这不是测试终止条件的好方法,但它使函数更简单。
#include <iostream>
#include <iomanip>
double mod_pi(double x) {
static const double two_pi = 3.14159265358979 * 2;
const int q = static_cast<int>(x / two_pi + 0.5);
return x - two_pi * q;
}
double func_sin(double x) {
x = mod_pi(x);
double sum = 0;
double a = 1; // 2*n+1 [1, 3, 5, 7, ...]
double b = x; // x^a
double c = 1; // (2*n+1)!
const double x_sq = x * x;
for(;;) {
const double tp = b / c;
// update for negative term
c *= (a+1) * (a+2);
a += 2;
b *= x_sq;
const double tn = b / c;
const double ns = tp - tn + sum;
if(ns == sum) return ns;
sum = ns;
// update for positive term (at top of loop)
c *= (a+1) * (a+2);
a += 2;
b *= x_sq;
}
}
int main() {
const double y = func_sin(-0.858407346398077);
std::cout << std::setprecision(13) << y << std::endl;
}