Nâng cao sức mạnh


12

Thử thách

Thách thức là viết một chương trình lấy một số dươnga và một số khác khôngb và đầu ra a^b(tăng lên sức mạnh b). Bạn chỉ có thể sử dụng + - * / abs()như các hàm toán tử / toán tử. Chúng chỉ có thể được áp dụng cho các giá trị vô hướng, nhưng không áp dụng cho toàn bộ danh sách hoặc mảng.

Ví dụ:

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

Có liên quan: http://xkcd.com/217/

Chi tiết

Bạn có thể viết một hàm hoặc một cấu trúc tương tự để sử dụng trong bàn điều khiển. Nếu bạn không thể sử dụng đầu vào giao diện điều khiển, bạn có thể giả sử rằng cả hai số được lưu trong các biến và ouptut thông qua đầu ra tiêu chuẩn hoặc ghi vào một tệp. Đầu ra phải chính xác đến ít nhất 4 chữ số có nghĩa. Bạn có thể giả định rằng cả hai abđều khác. Thời gian chạy hơn 1 phút không đáng kể là không thể chấp nhận được. Số byte ít nhất sẽ giành chiến thắng. Hãy giải thích chương trình của bạn và thuật toán của bạn.

EDIT: Chỉ có cơ sở tích cực phải được xem xét. Bạn có thể giả định a>0. Xin lưu ý rằng cả hai số không phải là số nguyên !!!


3
Bạn đang yêu cầu chúng tôi tăng lên một quyền lực thập phân? Giống như nói, 4,5 ^ 4,5?
fuandon

1
Điều này có nghĩa là chúng ta cũng phải xuất số ảo nếu cơ sở là âm?
bebe

1
Đầu ra -0.5 ** 0.5phải là gì?
Dennis

Ok tôi đã không nghĩ về trường hợp đó, cảm ơn bạn: Các cơ sở tiêu cực không được thực hiện chính xác. @fuandon chính xác, số thực có thể có số thập phân (ít nhất là trong hầu hết các ngôn ngữ lập trình =)
flawr

Tôi muốn thêm trường hợp thử nghiệm với b <0: `4,5 ^ -4,5 = 0,0011496 '
edc65

Câu trả lời:


3

Con trăn, 77

Như với một số câu trả lời khác, điều này dựa trên log và exp. Nhưng các hàm được tính bằng cách giải số bằng các phương trình vi phân thông thường.

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

Liệu nó có thỏa mãn yêu cầu? Đối với các ví dụ trong câu hỏi, có. Đối với a lớn, nó sẽ mất một thời gian rất dài. Đối với a hoặc b lớn, nó sẽ trở nên không chính xác.

Ví dụ:

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

Cập nhật: flawr yêu cầu chi tiết hơn về toán học vì vậy bạn đến đây. Tôi đã xem xét các vấn đề giá trị ban đầu sau đây:

  • x '(t) = x (t), với x (0) = 1. Giải pháp là exp (t).
  • y '(t) = by (t), với y (0) = 1. Giải pháp là exp (bt).

Nếu tôi có thể tìm giá trị của t sao cho x (t) = a, thì tôi sẽ có y (t) = exp (bt) = a ^ b. Cách đơn giản nhất để giải quyết vấn đề giá trị ban đầu là phương pháp Euler . Bạn tính đạo hàm mà hàm được cho là có, rồi thực hiện một bước, theo hướng của đạo hàm và tỷ lệ với nó, nhưng được chia tỷ lệ bởi một hằng số nhỏ. Vì vậy, đó là những gì tôi làm, thực hiện các bước nhỏ cho đến khi x lớn bằng a, và sau đó xem y là gì tại thời điểm đó. Chà, đó là cách tôi nghĩ về nó. Trong mã của tôi, t không bao giờ được tính toán rõ ràng (nó là 1e-7 * số bước của vòng lặp while) và tôi đã lưu một số ký tự bằng cách thực hiện các phép tính cho x bằng một thay thế.


Trông thật tuyệt, tôi rất vui khi thấy một cách tiếp cận khác! Bạn có thể cho chúng tôi biết thêm một chút về các phương trình vi phân này không? Nói chung tôi biết chúng là gì nhưng tôi không thể hiểu chương trình của bạn sử dụng chúng như thế nào =)
flawr

@flawr: OK, tôi đã cập nhật thêm một số chi tiết về toán học.
hâm nóng

6

JavaScript (E6) 155 174 191

Chỉnh sửa 2 Theo đề xuất của @bebe, sử dụng chức năng đệ quy (thực hiện kém hơn nhưng ngắn hơn)
Chức năng R thay đổi một chút để tránh 'quá nhiều đệ quy' Bộ
thử nghiệm được thêm vào. Hàm hoạt động tốt cho các cơ sở <3000 và số mũ trong phạm vi -50..50.
Chỉnh sửa Golf nhiều hơn và chính xác hơn

Bất kỳ số thực nào cũng có thể gần đúng với một số hữu tỷ (và số 'thực' theo tiêu chuẩn của IEEE lưu trữ các số hữu tỷ trên thực tế). Bất kỳ số hữu tỷ nào cũng có thể được biểu thị dưới dạng phân số a / b với số nguyên a và b. x ^ (a / b) là gốc b của (x ^ a) hoặc (gốc b của x) ^ a. Số mũ lũy thừa khá dễ dàng bằng bình phương. Root số nguyên có thể được xấp xỉ bằng các phương pháp số.

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)
)

Kiểm tra trong bảng điều khiển FireFox hoặc 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))
}

Công việc tốt, không chính xác khủng khiếp nhưng thuật toán rất hay =)
flawr

Bạn có thể giải thích điều này e&1&&(r*=b)không, ngoại trừ nhân rvới b?
flawr

1
@flawrif(e&1 != 0) r *= b
bebe

Cảm ơn, tôi đã không nhận thức được việc khai thác đó, nhưng nó có vẻ là một trò hay cho việc chơi gôn =)
flawr

1
đây là mã làm việc: 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))(tôi phải mệt)
bebe

6

Haskell, 85 90

Thuật toán exp-log tiêu chuẩn. Bây giờ với tên khác, loại bỏ một vài ký tự:

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]

raisebây giờ được gọi (%), hoặc %trong ký hiệu infix, thậm chí làm cho việc sử dụng nó tiêu thụ ít byte hơn:4.5%(-4.5)

Phiên bản không được sử dụng cũng chỉ sử dụng 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]

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)

Ví dụ:

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

Sử dụng loạt Taylor.
b^x = 1 + ln(b)*x/1! + (ln(b)*x)^2/2! + (ln(b)*x)^3/3! + (ln(b)*x)^4/4! + ...
với xấp xỉ logarit tự nhiên :
ln(b) = (1-1/x) + (1-1/x)^2/2 + (1-1/x)^3/3 + (1-1/x)^4/4 + ...

Tôi đã sử dụng 128 lần lặp để tính toán b^x(nhiều lần lặp lại là khó khăn do yếu tố) và 262144 lần lặp choln(b)


Có lẽ bạn nên chơi gôn ít hơn nhưng thêm độ chính xác: e(80,5) ->1555962210.2240903- nên là 3276800000
edc65

@ edc65, bạn đã đúng, đã sửa thêm 5 ký tự nữa.
Michael M.

1
Thật tuyệt khi thấy một số cách tiếp cận khác nhau!
flawr

3

sân golf 120

Tôi sử dụng thực tế là

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

và viết riêng log& expchức năng của tôi . Các giá trị abcần được nhập vào dòng mới khi chạy trong thiết bị đầu cuối:

\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)))

Chạy mẫu:

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

Một phiên bản Lua vô danh là,

-- 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)

Bạn có thể cung cấp một số ví dụ đầu ra?
flawr

@flawr: Tôi cho rằng tôi có thể ... và giờ đã hoàn thành
Kyle Kanos
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.