0

基本関数を計算するときは、定数変更を適用します。特にexp(x)の実装にあります。これらのすべての実装では、ln(2)による修正は2つのステップで行われます。 (2)LNは、二つの数に分割されています。私はそれを丸め効果を避けるために知っているIEEE-754倍精度と分割方法

blablabla -= ln2p1 
blablabla -= ln2p2 

static const double ln2p1 = 0.693145751953125; 
static const double ln2p2 = 1.42860682030941723212E-6; 
// then ln(2) = ln2p1 + ln2p2 

はその後LNとの任意の計算は、(2)によって行われます。しかし、なぜこの2つの数字が特別なのですか?あなたはこの2つの数字をどうやって得るのか考えている人もいます。

ありがとうございました!

最初のコメントの後、私はより重要な、そして非常に奇妙な質問でこの投稿を完成させます。私はチームと一緒に仕事をしており、ln(2)という数字を2つの数字に分割して精度を倍にすることには同意します。このために、2つの変換は、最初のものを適用されます。

1) c_h = floor(2^k ln(2))/2^k 
2) c_l = ln(2) - c_h 

kはフロートkは9上に固定されているため見た目にCephesライブラリー(〜1980年)に好きな、精度を示し、ダブル、また16 16長い間の長い二倍(なぜ私が知らないのか)。したがって、doubleの場合、c_hは16ビットの精度を持ちますが、c_lの精度は52ビットです。

これから、私は次のプログラムを書いて、52ビットの精度でc_hを決定します。

#include <iostream> 
#include <math.h> 
#include <iomanip> 

enum precision { nine = 9, sixteen = 16, fiftytwo = 52 }; 

int64_t k_helper(double x){ 
    return floor(x/log(2)); 
} 

template<class C> 
double z_helper(double x, int64_t k){ 
    x -= k*C::c_h; 
    x -= k*C::c_l; 
    return x; 
} 

template<precision p> 
struct coeff{}; 

template<> 
struct coeff<nine>{ 
    constexpr const static double c_h = 0.693359375; 
    constexpr const static double c_l = -2.12194440e-4; 
}; 

template<> 
struct coeff<sixteen>{ 
    constexpr const static double c_h = 6.93145751953125E-1; 
    constexpr const static double c_l = 1.42860682030941723212E-6; 
}; 

template<> 
struct coeff<fiftytwo>{ 
    constexpr const static double c_h = 0.6931471805599453972490664455108344554901123046875; 
    constexpr const static double c_l = -8.78318343240526578874146121703272447458793199905066E-17; 
}; 


int main(int argc, const char * argv[]) { 

    double x = atof(argv[1]); 
    int64_t k = k_helper(x); 

    double z_9 = z_helper<coeff<nine> >(x,k); 
    double z_16 = z_helper<coeff<sixteen> >(x,k); 
    double z_52 = z_helper<coeff<fiftytwo> >(x,k); 


    std::cout << std::setprecision(16) << " 9 bits precisions " << z_9 << "\n" 
             << " 16 bits precisions " << z_16 << "\n" 
             << " 52 bits precisions " << z_52 << "\n"; 



    return 0; 

}

私は異なる値のセットのために、今計算した場合、私は得る:

bash-3.2$ g++ -std=c++11 main.cpp 
bash-3.2$ ./a.out 1 
9 bits precisions 0.30685281944 
16 bits precisions 0.3068528194400547 
52 bits precisions 0.3068528194400547 
bash-3.2$ ./a.out 2 
9 bits precisions 0.61370563888 
16 bits precisions 0.6137056388801094 
52 bits precisions 0.6137056388801094 
bash-3.2$ ./a.out 100 
9 bits precisions 0.18680599936 
16 bits precisions 0.1868059993678755 
52 bits precisions 0.1868059993678755 
bash-3.2$ ./a.out 200 
9 bits precisions 0.37361199872 
16 bits precisions 0.3736119987357509 
52 bits precisions 0.3736119987357509 
bash-3.2$ ./a.out 300 
9 bits precisions 0.56041799808 
16 bits precisions 0.5604179981036264 
52 bits precisions 0.5604179981036548 
bash-3.2$ ./a.out 400 
9 bits precisions 0.05407681688 
16 bits precisions 0.05407681691155647 
52 bits precisions 0.05407681691155469 
bash-3.2$ ./a.out 500 
9 bits precisions 0.24088281624 
16 bits precisions 0.2408828162794319 
52 bits precisions 0.2408828162794586 
bash-3.2$ ./a.out 600 
9 bits precisions 0.4276888156 
16 bits precisions 0.4276888156473074 
52 bits precisions 0.4276888156473056 
bash-3.2$ ./a.out 700 
9 bits precisions 0.61449481496 
16 bits precisions 0.6144948150151828 
52 bits precisions 0.6144948150151526 

xは300差が現れるよりも大きくなったときにそれが好き。私はgnulibcの実装に見ていた

http://osxr.org:8080/glibc/source/sysdeps/ieee754/ldbl-128/s_expm1l.c

現在、それはIEEE規格に、

は、まあ、私はおそらく何かが足りないのですC_H(ライン84)のための16ビットの予知を使用しており、私はglibcの精度の誤差を想像することはできません。どう思いますか ?

ベスト、

答えて

0

ln2p1は正確に65536分の45426です。これはround(65536 * ln(2))によって得ることができます。 ln2p2は単に残りの部分です。したがって、この2つの数について特別なものは、分母65536(2 )です。私はこの定数を使用して、ほとんどのアルゴリズムは戻って2 が選ばれた理由をおそらく説明する16ビット・コンピューティングはまだ支配された場所最初の1984年にリリースされたcephesライブラリ、に遡ることができる見つけたものから

+0

ハムの面白いコメント、少なくとも私は歴史的な答えの始まりを持っています。それは本当に私の質問に答えるものではありません。私はコンピュータの科学者が浮動小数点数について知っておくべきことおそらくこの2^16の理由は...続きます –