Підняти на потужність


12

Виклик

Challenge - це написання програми, яка приймає додатні числа aта ненульове число bта виводить a^b(підняте на потужність b). Ви можете використовувати лише + - * / abs()як математичні функції / оператори. Вони можуть застосовуватися лише до скалярних значень, але не до цілих списків чи масивів.

Приклади:

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

Відповідне: http://xkcd.com/217/

Деталі

Ви можете написати функцію або подібну конструкцію для використання в консолі. Якщо ви не можете використовувати введення консолі, ви можете припустити, що обидва числа зберігаються у змінних та виводяться за допомогою стандартного виводу або запису у файл. Вихід повинен бути правильним щонайменше 4 значними цифрами. Можна припустити, що і те, aі інше bє ненульовим. Час виконання значно більше 1 хвилини не прийнятний. Найменша кількість байтів виграє. Поясніть, будь ласка, свою програму та свій алгоритм.

EDIT: Необхідно враховувати лише позитивні основи . Можна припустити a>0. Будьте в курсі, що обидва числа не повинні бути цілими числами !!!


3
Ти просиш нас підняти до десяткової потужності? Як скажімо, 4,5 ^ 4,5?
fuandon

1
Чи означає це, що ми також повинні виводити уявні числа, якщо база негативна?
bebe

1
Яким повинен бути вихід -0.5 ** 0.5?
Денніс

Добре, я не думав про цей випадок, дякую: негативні основи не повинні бути належним чином виконані. @fuandon точно, реальні числа можуть мати десятичні цифри (принаймні, у більшості мов програмування =)
недолік

Я хотів би додати тестовий випадок з b <0: `4,5 ^ -4,5 = 0,0011496 '
edc65

Відповіді:


3

Пітона, 77

Як і в деяких інших відповідях, це базується на log та exp. Але функції обчислюються чисельним рішенням звичайних диференціальних рівнянь.

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

Чи відповідає це вимогам? Для прикладів у питанні, так. Для великих людей це займе дуже багато часу. Для великих a або b це стане неточним.

Приклади:

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

Оновлення: flawr попросив більш детально про математику, так що ось ви йдете. Я розглянув такі початкові проблеми:

  • x '(t) = x (t), при x (0) = 1. Рішення є exp (t).
  • y '(t) = через (t), при y (0) = 1. Рішення є exp (bt).

Якщо я можу знайти значення t таке, що x (t) = a, то у мене буде y (t) = exp (bt) = a ^ b. Найпростіший спосіб чисельного вирішення початкової задачі - метод Ейлера . Ви обчислюєте похідну, якою повинна бути функція, а потім зробите крок у напрямку похідної та пропорційній їй, але масштабується крихітною константою. Отже, це я роблю, робіть крихітні кроки, поки х не стане великим, як а, а потім подивіться, що у цей час є. Ну, ось так я і думав про це. У моєму коді t ніколи не обчислюється явно (це 1e-7 * кількість кроків циклу while), і я зберег деякі символи, зробивши обчислення для x із замість цього.


Це виглядає чудово, я радий бачити інший підхід! Чи можете ви розповісти нам трохи більше про ці диференціальні рівняння? Я взагалі знаю, що вони є, але я не зміг зрозуміти, як ви їх використовуєте програмою =)
flawr

@flawr: Добре, я оновив ще кілька деталей про математику.
розігріто

6

JavaScript (E6) 155 174 191

Редагувати 2 Як запропонував @bebe, використовуючи рекурсивну функцію (виконана гірше, але коротше)
Трохи змінена функція R, щоб уникнути "занадто багато рекурсії"
Додано тестовий набір. Ця функція добре працює для баз <3000 та експонента в діапазоні -50..50.
Більше редагуйте Golfed та покращуйте точність

Будь-яке дійсне число може бути приблизним до раціонального числа (а фактичні "реальні" числа IEEE фактично зберігають раціональні факти). Будь-яке раціональне число може бути виражене дробом a / b з цілими числами a і b. x ^ (a / b) - корінь b (x ^ a) або (корінь b з x) ^ a. Експоненціація цілочисень досить проста шляхом квадратування. Корінь цілого числа можна наблизити за допомогою числових методів.

Код

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

Тест в консолі FireFox або 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))
}

Хороша робота, не дуже точна, але алгоритм приємний =)
недолік

Чи можете ви пояснити, що це e&1&&(r*=b)робить, крім множення rна b?
недолік

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

Дякую, я не знав про цей подвиг, але, здається, це приємно для гольфу =)
flawr

1
ось робочий код: 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))(я повинен бути втомився)
bebe

6

Хаскелл, 85 90

Стандартний алгоритм exp-журналу. Тепер з іншою назвою, голіючи ще кілька символів:

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]

raiseтепер називається (%)або %в інфіксації, навіть змушує його використовувати менше байтів:4.5%(-4.5)

Негольфірована версія також використовує всього 172 байти:

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 байти

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)

Приклади:

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

Використовуйте серію Тейлор.
b^x = 1 + ln(b)*x/1! + (ln(b)*x)^2/2! + (ln(b)*x)^3/3! + (ln(b)*x)^4/4! + ...
з наближенням природного логарифму :
ln(b) = (1-1/x) + (1-1/x)^2/2 + (1-1/x)^3/3 + (1-1/x)^4/4 + ...

Для обчислення я використав 128 ітерацій b^x(більше ітерацій важко через факториал) і 262144 ітерацій дляln(b)


Можливо, вам слід поменше гольфу, але додайте більше точності: e(80,5) ->1555962210.2240903- має бути 3276800000
edc65

@ edc65, ти маєш рацію, визначивши ще 5 символів.
Майкл М.

1
Дуже приємно бачити кілька різних підходів!
flawr

3

гольфлуа 120

Я використовую те, що

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

і написав власні log& expфункції. Значення aта bпотрібно вводити в нових рядках під час запуску в терміналі:

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

Проби:

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

Негольована версія Луа -

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

Чи можете ви надати деякі приклади результатів?
flawr

@flawr: Я гадаю, що можу ... і зараз це зроблено
Кайл Канос
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.