Поднять к власти


12

Вызов

Задача - написать программу, которая принимает положительные числа 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 минуту, недопустимо. Наименьшее количество байтов выиграет. Пожалуйста, объясните вашу программу и ваш алгоритм.

РЕДАКТИРОВАТЬ: Только положительные основы должны быть рассмотрены. Вы можете предположить a>0. Помните, что оба числа не должны быть целыми числами !!!


3
Вы просите нас поднять до десятичной степени? Как, скажем, 4,5 ^ 4,5?
Fuandon

1
Значит ли это, что мы должны выводить мнимые числа, если база отрицательна?
bebe

1
Каким должен -0.5 ** 0.5быть выход ?
Деннис

Хорошо, я не думал об этом случае, спасибо: отрицательные основы не должны быть правильно реализованы. @fuandon точно, действительные числа могут иметь десятичные дроби (по крайней мере, в большинстве языков программирования =)
flawr

Я хотел бы добавить контрольный пример с b <0: `4.5 ^ -4.5 = 0.0011496 '
edc65

Ответы:


3

Python, 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) = by (t), где y (0) = 1. Решение - exp (bt).

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


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

@flawr: Хорошо, я обновил некоторые подробности о математике.
разогрев

6

JavaScript (E6) 155 174 191

Редактировать 2 В соответствии с предложением @bebe, использование рекурсивной функции (работает хуже, но короче).
Немного изменена функция R, чтобы избежать «слишком большой рекурсии».
Добавлен набор тестов. Функция хорошо работает для базисов <3000 и экспоненты в диапазоне -50..50.
Редактировать Golff больше и точность

Любое действительное число может быть аппроксимировано рациональным числом (а стандартные «действительные» числа 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))
}

Хорошая работа, не очень точная, но алгоритм хорош =)
flawr

Можете ли вы объяснить, что это e&1&&(r*=b)делает, кроме умножения rна b?
flawr

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-log. Теперь с другим именем, сбривая еще несколько символов:

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)

Версия ungolfed также использует всего 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

Golflua 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

Безголосая версия Lua,

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