c++ - 指数近似不适用于小输入或大输入

标签 c++ approximation exp

基于裁缝级数的指数逼近代码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;
    }

“近似 e^x”中看似相似问题的解决方案 Approximate e^x没有解决这个问题:

  • 基于 Remez 和 Pade 近似的解决方案只能提供有限范围内的精度 (https://stackoverflow.com/a/6985347/5750612)
  • e^x = 2 x/ln(2) 归结为 pow 的近似值,我找不到精确值
  • 定制系列不适用于小输入和大输入
  • expf_fast 解决方案在所有范围内产生更均匀的误差,但它仍然太大(范围末尾约 20%)

最佳答案

使用 Tailor 展开找到近似值的最简单方法之一是检查收敛速度,只需添加一个新的更高项并确认结果。

这是支持上述想法的我的 C++ 代码。

#include <iostream>
#include <cmath>

double my_exp(const double x, const double x0 = 0, const double ncut = 1e-3)
{
    double res = 1.; 
    double addterm = (x - x0);
    size_t norder = 1; 

    while(true)
    {
        double res_update = res + addterm;
        if(std::abs(res_update - res)/std::abs(res) < ncut){
            break;
        }
        norder += 1;
        addterm *= (x - x0)/norder;
        res = res_update;
    }

    return res;
}


int main(int argc, char* argv[])
{
    const double x = std::atof(argv[1]);
    const double approxi = my_exp(x);

    const double exactResult = std::exp(x);

    std::cout<<"approxi : "<< approxi<<std::endl;
    std::cout<<"exact : "<< exactResult<<std::endl;

    std::cout<<"err: "<< (1 - std::abs(approxi/exactResult))*100 <<std::endl;

    return 0;
}

关于c++ - 指数近似不适用于小输入或大输入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45929914/

相关文章:

python - Python 中复数除法的停止近似

c - 我*不*想要函数 exp 的正确舍入

c++ - 每线程单例使用 thread_local 存储

c++ - 我如何获得 giomm-2.4 软件包?

c++ - Ada 数字代码未通过隐藏测试

python - math.exp() 定义在 python 源代码的哪个位置?

c - 如何在 NASM for Linux 中正确使用 C 函数 "Exp"?

c++ - 专用 vector 模板的大括号初始化

algorithm - TSP变体的近似算法,固定起点和终点,但起点+每个顶点允许多次访问

algorithm - 最小化颜色 : a variation of the knapsack algorithm?