2017-08-29 3 views
0

テーラー級数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% 

Iエラーできるだけ大きな範囲にわたって未満、1%の誤差で近似する必要があります。どのようにこれを達成するための任意のアイデアですか?

私の小さなテストコードは以下の通りです:レメズとパデ近似に基づい

  • ソリューション:「おおよそのE^x」はApproximate e^xは、この問題を解決していませんから、一見似た質問から

    #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; 
        } 
    

    ソリューション(https://stackoverflow.com/a/6985347/5750612

  • e^x = 2 x/ln(2)はpowの近似に来て、正確なものを見つけることができませんでした
  • (範囲の終わりに〜20%)
  • テーラーシリーズは小さく、大きな入力に対しては機能しません
  • expf_fastソリューションは、すべての範囲を越えてより均一なエラーが発生しますが、それはまだ大きすぎる
+0

[おおよそのE^x]は(https://stackoverflow.com/questions/6984440/approximate-ex) – jodag

答えて

0

の1 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; 
} 
+0

の可能性のある重複したこの1つは非常にうまく動作するようです。私のテストコードから使用した場合、結果はすべての範囲のパーセントの割合です。 in = -12 error = 00000000.03% in = -11.00 error = 00000000.05% in = -10.00 error = 00000000.02% in -9.00 error IN = -8.00誤差= 00000000.07% に= -7.00誤差= 00000000.03% ... = 00000000.04% IN = 7.00誤差= 00000000.10% IN = 8.00誤差= 00000000.16% IN = 9.00誤差= 00000000.11% in = 10.00 error = 00000000.16% in = 11.00 error = 00000000.10% in = 12.00 error = 00000000.15% – picant

関連する問題