Efisien 10 untuk power double

Oct 22 2020

Saya harus menaikkan 10 pangkat dua kali lipat.

Apakah ada cara yang lebih efisien untuk melakukan ini daripada dengan perpustakaan matematika pow(10,double)? Jika itu penting, ganda saya selalu negatif antara -5 dan -11.

Saya berasumsi pow (double, double) menggunakan algoritma yang lebih umum daripada yang dibutuhkan untuk pow (10, double) dan karena itu mungkin bukan metode tercepat. Mengingat beberapa jawaban di bawah ini, mungkin itu adalah asumsi yang salah.

Adapun alasannya, untuk interpolasi logartihmic. Saya memiliki tabel nilai x dan y. Objek saya memiliki nilai x yang diketahui (yang hampir selalu ganda).

double Dbeta(struct Data *diffusion, double per){
  double frac;
  while(per>diffusion->x[i]){
      i++;
  }
  frac = (per-diffusion->x[i-1])/(diffusion->x[i]-diffusion->x[i-1]);
  return pow(10,log10DB[i-1] + frac * (log10DB[i]-log10DB[i-1]));
}

Fungsi ini sering dipanggil. Saya telah diberitahu untuk melihat profil, jadi itulah yang akan saya lakukan pertama kali.

Saya baru saja diberi tahu bahwa saya bisa menggunakan logaritma natural daripada basis 10, yang jelas benar. (kebodohan saya terkadang mengherankan bahkan pada diri saya sendiri.)

Setelah mengganti semuanya dengan logaritma natural semuanya berjalan sedikit lebih cepat. Dengan pembuatan profil (yang merupakan kata baru yang saya pelajari hari ini) saya menemukan 39% dari kode saya dihabiskan di fungsi exp, jadi bagi mereka yang bertanya-tanya apakah sebenarnya bagian inilah yang menghambat kode saya.

Jawaban

3 PascalGetreuer Oct 22 2020 at 14:58

Ya, fungsi pow lambat (kira-kira 50x biaya kelipatan, bagi mereka yang meminta tolok ukur).

  • Dengan beberapa trik log / eksponen, kita dapat mengekspresikan 10 ^ x sebagai

    10^x = exp(log(10^x)) = exp(x * log(10)).
    

    Jadi Anda bisa menerapkan 10 ^ x dengan exp(x * M_LN10), yang seharusnya lebih efisien daripada pow.

  • Jika akurasi ganda tidak penting, gunakan versi float dari fungsi expf(atau powf), yang seharusnya lebih efisien daripada versi ganda.

  • Jika akurasi kasarnya Ok, hitung dahulu tabel pada rentang [-5, -11] dan lakukan pencarian cepat dengan interpolasi linier.

Beberapa benchmark (menggunakan glibc 2.31):

Benchmark                Time
---------------------------------
pow(10, x)               15.54 ns
powf(10, x)               7.18 ns
expf(x * (float)M_LN10)   3.45 ns
5 TomKarzes Oct 22 2020 at 14:53

Karena pow(10.0, n)itu harus lebih cepat untuk disetel c = log(10.0), yang dapat Anda hitung sekali, kemudian gunakan exp(c*n), yang seharusnya jauh lebih cepat daripada pow(10.0, n)(yang pada dasarnya melakukan hal yang sama secara internal, kecuali itu akan menghitung log(10.0)berulang-ulang dan bukan hanya sekali). Selain itu, mungkin tidak banyak lagi yang dapat Anda lakukan.