【发布时间】:2017-08-29 02:39:26
【问题描述】:
基于裁缝系列https://en.wikipedia.org/wiki/Taylor_series 的指数近似代码适用于零附近的输入,但在向任一方向移动更远时完全无用。下面是我的小测试代码的输出,它计算 -12 到 12 范围内的输入的 exp 并与 std::exp 结果相比打印错误,并且边界处的错误很大。例如 -12 输入的错误大约是 148255571469%:
in = -12 error = 148255571469.28%
in = -11.00 error = 18328703925.31%
in = -10.00 error = 2037562880.10%
in = -9.00 error = 199120705.27%
in = -8.00 error = 16588916.06%
in = -7.00 error = 01128519.76%
in = -6.00 error = 00058853.00%
in = -5.00 error = 00002133.29%
in = -4.00 error = 00000045.61%
in = -3.00 error = 00000000.42%
in = -2.00 error = 00000000.00%
in = -1.00 error = 00000000.00%
in = 0.00 error = 00000000.00%
in = 1.00 error = 00000000.00%
in = 2.00 error = 00000000.00%
in = 3.00 error = 00000000.00%
in = 4.00 error = 00000000.03%
in = 5.00 error = 00000000.20%
in = 6.00 error = 00000000.88%
in = 7.00 error = 00000002.70%
in = 8.00 error = 00000006.38%
in = 9.00 error = 00000012.42%
in = 10.00 error = 00000020.84%
in = 11.00 error = 00000031.13%
in = 12.00 error = 00000042.40%
我需要在尽可能大的范围内以小于 1% 的误差进行近似。任何想法如何实现这一目标?
我的小测试代码如下:
#include <cmath>
#include <iostream>
#include <iomanip>
double my_exp(double x) //based on https://en.wikipedia.org/wiki/Exponential_function
{
double res = 1. + x, t = x;
unsigned long factorial = 1;
for (unsigned char i = 2; i <= 12; ++i)
{
t *= x, factorial *= i;
res += t / factorial;
}
return res;
}
int main(int argc, char* argv[])
{
for (double in = -12; in <= 12; in += 1.)
{
auto error = std::abs(my_exp(in) - std::exp(in));
auto percent = error * 100. / std::exp(in);
std::cout << "in = " << in << " error = "
<< std::fixed << std::setw( 11 ) << std::setprecision( 2 )
<< std::setfill( '0' ) << percent << "%" << std::endl;
}
return 0;
}
来自“Approximate e^x”Approximate e^x 的看似相似问题的解决方案无法解决此问题:
- 基于 Remez 和 Pade 近似的解决方案只能提供有限范围内的精度 (https://stackoverflow.com/a/6985347/5750612)
- e^x = 2 x/ln(2) 归结为 pow 的近似值,我找不到精确的值
- tailor series 不适用于大小输入
- expf_fast 解决方案在所有范围内产生更均匀的误差,但仍然太大(在范围结束时约为 20%)
【问题讨论】:
-
Approximate e^x的可能重复
标签: c++ approximation exp