Angkat ke Kekuatan

12

Tantangan

Tantangan menulis sebuah program yang membutuhkan positif angka adan nol nomor bdan output a^b(a pangkat b). Anda hanya dapat menggunakan + - * / abs()fungsi / operator matematika. Ini hanya bisa diterapkan pada nilai skalar, tetapi tidak untuk seluruh daftar atau array.

Contoh:

1.234 ^ 5.678 = 3.29980
4.5   ^ 4.5   = 869.874
4.5   ^-4.5   = 0.00114959

Relevan: http://xkcd.com/217/

Detail

Anda dapat menulis fungsi atau konstruksi serupa untuk digunakan di konsol. Jika Anda tidak dapat menggunakan input konsol, Anda dapat mengasumsikan bahwa kedua angka tersebut disimpan dalam variabel dan di-output melalui output standar atau menulis ke file. Output harus benar minimal 4 digit signifikan. Anda dapat berasumsi bahwa keduanya adan bbukan nol. Runtime lebih dari 1 menit secara signifikan tidak dapat diterima. Jumlah byte terkecil akan menang. Tolong jelaskan program dan algoritma Anda.

EDIT: Hanya basis positif yang harus dipertimbangkan. Anda bisa berasumsi a>0. Ketahuilah bahwa kedua angka tidak harus bilangan bulat !!!

cacat
sumber
3
Apakah Anda meminta kami untuk meningkatkan daya desimal? Seperti katakanlah, 4,5 ^ 4,5?
fuandon
1
Apakah ini berarti kita juga harus mengeluarkan bilangan imajiner jika basisnya negatif?
bebe
1
Apa yang harus menjadi output -0.5 ** 0.5?
Dennis
Ok saya tidak memikirkan hal itu, terima kasih: Basis negatif tidak boleh diimplementasikan dengan benar. @ fuandon persisnya, bilangan real dapat memiliki desimal (setidaknya dalam sebagian besar bahasa pemrograman =)
flawr
Saya ingin menambahkan test case dengan b <0: `4.5 ^ -4.5 = 0.0011496 '
edc65

Jawaban:

3

Python, 77

Seperti beberapa jawaban lain ini didasarkan pada log dan exp. Tetapi fungsi dihitung dengan memecahkan persamaan diferensial biasa secara numerik.

def f(a,b,y=1):
 if a<1:a=1/a;b=-b
 while a>1:a/=1e-7+1;y*=b*1e-7+1
 return y

Apakah memenuhi persyaratan? Untuk contoh-contoh dalam pertanyaan, ya. Untuk yang besar, itu akan memakan waktu yang sangat lama. Untuk a atau b besar, itu akan menjadi tidak akurat.

Contoh:

a            b            f(a, b)      pow(a, b)      <1e-5 rel error?
       1.234        5.678       3.2998       3.2998   OK
         4.5          4.5      869.873      869.874   OK
         4.5         -4.5   0.00114959   0.00114959   OK
         0.5          0.5     0.707107     0.707107   OK
         0.5         -0.5      1.41421      1.41421   OK
          80            5  3.27679e+09   3.2768e+09   OK
     2.71828      3.14159      23.1407      23.1407   OK

Pembaruan: flawr meminta lebih detail tentang matematika jadi begini. Saya mempertimbangkan masalah nilai awal berikut:

  • x '(t) = x (t), dengan x (0) = 1. Solusinya adalah exp (t).
  • y '(t) = oleh (t), dengan y (0) = 1. Solusinya adalah exp (bt).

Jika saya dapat menemukan nilai t sehingga x (t) = a, maka saya akan memiliki y (t) = exp (bt) = a ^ b. Cara paling sederhana untuk menyelesaikan masalah nilai awal secara numerik adalah metode Euler . Anda menghitung turunan fungsi seharusnya, dan kemudian mengambil, langkah, ke arah turunan, dan sebanding dengan itu, tetapi diskalakan oleh konstanta kecil. Jadi itulah yang saya lakukan, ambil langkah kecil sampai x sebesar a, dan kemudian lihat apa y pada saat itu. Yah, begitulah cara saya memikirkannya. Dalam kode saya, t tidak pernah dihitung secara eksplisit (itu adalah 1e-7 * jumlah langkah dari while loop), dan saya menyimpan beberapa karakter dengan melakukan perhitungan untuk x dengan gantinya.

dipanaskan kembali
sumber
Itu terlihat hebat, saya senang melihat pendekatan lain yang berbeda! Bisakah Anda ceritakan lebih banyak tentang persamaan diferensial ini? Saya tahu secara umum apa itu tetapi saya tidak dapat mengetahui bagaimana program Anda menggunakannya =)
flawr
@ flawr: OK, saya memperbarui dengan beberapa detail lebih lanjut tentang matematika.
dipanaskan
6

JavaScript (E6) 155 174 191

Sunting 2 Seperti yang disarankan oleh @bebe, menggunakan fungsi rekursif (berkinerja lebih buruk tapi lebih pendek)
Sedikit mengubah fungsi R untuk menghindari 'terlalu banyak rekursi'.
Test suite ditambahkan. Fungsi berkinerja baik untuk pangkalan <3000 dan eksponen dalam kisaran -50..50.
Sunting Golf lebih presisi dan lebih baik

Setiap bilangan real dapat diperkirakan dengan bilangan rasional (dan bilangan rasional 'nyata' standar IEEE sebenarnya). Setiap bilangan rasional dapat dinyatakan sebagai pecahan a / b dengan a dan b bilangan bulat. x ^ (a / b) adalah root b dari (x ^ a) atau (root b of x) ^ a. Eksponensial integer cukup mudah dengan mengkuadratkan. Root integer dapat diperkirakan dengan menggunakan metode numerik.

Kode

P=(x,e)=>(
  f=1e7,e<0&&(x=1/x,e=-e),
  F=(b,e,r=1)=>e?F(b*b,e>>1,e&1?r*b:r):r,
  R=(b,e,g=1,y=1e-30,d=(b/F(g,e-1)-g)/e)=>d>y|d<-y?R(b,e,g+d,y/.99):g,
  F(R(x,f),e*f)
)

Tes di FireFox atau konsol FireBug

for (i=0;i<100;i++)
{
  b=Math.random()*3000
  e=Math.random()*100-50
  p1=Math.pow(b,e) // standard power function, to check
  p2=P(b,e)
  d=(p1-p2)/p1 // relative difference
  if (!isFinite(p2) || d > 0.001) 
    console.log(i, b, e, p1, p2, d.toFixed(3))
}
edc65
sumber
Kerja
Bisakah Anda menjelaskan apa e&1&&(r*=b)fungsinya, kecuali mengalikan rdengan b?
flawr
1
@ flawrif(e&1 != 0) r *= b
bebe
Terima kasih, saya tidak mengetahui tentang eksploitasi itu, tetapi sepertinya itu bagus untuk bermain golf =)
flawr
1
ini kode kerjanya: P=(x,e)=>(F=(b,e,r=1)=>e?F(b*b,e>>1,e&1?r*b:r):r,R=(b,e,g=1,y=1e-16,d=(b/F(g,e-1)-g)/e)=>d>y|d<-y?R(b,e,g+d):g,e<0&&(x=1/x,e=-e),f=1<<24,F(R(x,f),e*f))(saya pasti lelah)
bebe
6

Haskell, 85 90

Algoritma exp-log standar. Sekarang dengan nama yang berbeda, mengurangi beberapa karakter:

a%b|a>1=1/(1/a)%b|0<1=sum$scanl((/).((-b*foldr1(\n b->(1-a)*(b+1/n))c)*))1c
c=[1..99]

raisesekarang disebut (%), atau %dalam notasi infiks, bahkan membuat penggunaannya memakan lebih sedikit byte:4.5%(-4.5)

Versi ungolfed juga hanya menggunakan 172 byte:

raise a b | a > 1     = 1 / raise (1/a) b
          | otherwise = expo (-b* ln (1-a))

ln x = foldr1 (\n a -> x*a+x/n) [1..99]

expo x = sum $ scanl ((/) . (x*)) 1 [1..99]
TheSpanishInquisition
sumber
4

JS (ES6), 103 byte

t=(x,m,f)=>{for(r=i=s=u=1;i<1<<7+f;r+=s/(u=i++*(f?1:u)))s*=m;return r};e=(a,b)=>t(b,t(a,1-1/a,9)*b-b,0)

Contoh:

e(1.234,5.678) = 3.299798925315965
e(4.5,4.5)     = 869.8739233782269
e(4.5,-4.5)    = 0.0011495918812070608

Gunakan seri Taylor.
b^x = 1 + ln(b)*x/1! + (ln(b)*x)^2/2! + (ln(b)*x)^3/3! + (ln(b)*x)^4/4! + ...
dengan perkiraan logaritma natural :
ln(b) = (1-1/x) + (1-1/x)^2/2 + (1-1/x)^3/3 + (1-1/x)^4/4 + ...

Saya menggunakan 128 iterasi untuk menghitung b^x(iterasi lebih sulit karena faktorial) dan 262144 iterasi untukln(b)

Michael M.
sumber
Mungkin Anda harus bermain golf lebih sedikit tetapi menambahkan lebih banyak presisi: e(80,5) ->1555962210.2240903- seharusnya 3276800000
edc65
@ edc65, Anda benar, diperbaiki untuk 5 karakter lagi.
Michael M.
1
Sangat menyenangkan melihat beberapa pendekatan berbeda!
flawr
3

golflua 120

Saya menggunakan fakta itu

a^b = exp(log(a^b)) = exp(b*log(a))

dan menulis fungsi saya sendiri log& exp. Nilai-nilai adan bperlu dimasukkan pada baris baru saat dijalankan di terminal:

\L(x)g=0~@ i=1,50 c=(x-1)/x~@j=2,i c = c*(x-1)/x$g=g+c/i$~g$\E(x)g=1;R=1e7~@i=1,R g=g*(1+x/R)$~g$a=I.r()b=I.r()w(E(b*L(a)))

Sampel berjalan:

4.5, 4.5  ==> 869.87104890175
4.5, -4.5 ==> 0.0011495904124065
3.0, 2.33 ==> 12.932794624815
9.0, 0.0  ==> 1
2.0, 2.0  ==> 3.9999996172672

Versi Lua ungolfed adalah,

-- returns log
function L(x)
   g = 0
   for i=1,50 do
      c=(x-1)/x
      for j=2,i do
         c = c*(x-1)/x
      end
      g = g + c/i
   end
   return g
end

-- returns exp
function E(x)
   g=1;L=9999999
   for i=1,L do
      g=g*(1+x/L)
   end
   return g
end

a=io.read()
b=io.read()

print(E(b*L(a)))
print(a^b)
Kyle Kanos
sumber
Bisakah Anda memberikan beberapa contoh output?
flawr
@ flawr: Saya rasa saya bisa ... dan sekarang selesai
Kyle Kanos