提升力量


12

挑战

挑战是编写一个程序,该程序需要一个a和一个非零b并输出a^b(a升为幂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个有效数字。您可以假定ab均为非零值。超过1分钟的运行时间是不可接受的。最少的字节数将获胜。请说明您的程序和算法。

编辑:只需要考虑积极的基础。你可以假设a>0请注意,两个数字都不必是整数!!!


3
您是在要求我们提高小数点后乘幂吗?就像4.5 ^ 4.5吗?
Fuandon 2014年

1
这是否意味着如果基数为负,我们也必须输出虚数?
Bebe 2014年

1
输出应该-0.5 ** 0.5是什么?
丹尼斯

好的,我没有想到这种情况,谢谢:负基不能正确实现。@fuandon确切地,实数可以具有小数(至少在大多数编程语言中为=)
更加模糊的2014年

我想用b添加测试用例<0:`4.5 ^ -4.5 = 0.0011496'
edc65

Answers:


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,将需要很长时间。对于较大的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

更新:骗子要求提供有关数学的更多详细信息,因此您可以开始。我考虑了以下初始值问题:

  • 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。数值求解初值问题的最简单方法是欧拉方法。您可以计算出该函数应该具有的导数,然后导数的方向迈出一步,并与之成比例,但按微小常数缩放。这就是我要做的,采取微小的步骤直到x与a一样大,然后查看当时的y。好吧,这就是我的想法。在我的代码中,从未显式地计算过t(它是1e-7 * while循环的步数),我通过用a代替x进行计算来保存一些字符。


看起来不错,我很高兴看到另一种不同的方法!您能告诉我们更多关于这些微分方程的信息吗?我通常知道它们是什么,但是我无法弄清楚您的程序如何使用它们=)
更加模糊的

@flawr:好的,我更新了有关数学的更多详细信息。
2014年

6

JavaScript(E6)155174191

编辑2如@bebe所建议,使用递归函数(性能较差但更短)
略微更改了R函数,以避免添加“太多递归”
测试套件。该函数在<3000的底数和-50..50的指数范围内表现良好。
编辑高尔夫更多,更好的精度

任何实数都可以与有理数近似(而IEEE标准“实”数实际上存储有理)。任何有理数都可以表示为a / b与a和b整数的分数。x ^(a / b)是(x ^ a)的根b或(x的根b)^ 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)呢,除了乘rb
瑕疵的

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

谢谢,我当时还没有意识到这一漏洞,但是对于高尔夫来说,这似乎是一个不错的漏洞。=)
漏洞更严重

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 2014年

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)

非高尔夫版本也仅使用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个字符。
Michael M.

1
很高兴看到一些不同的方法!
瑕疵的

3

golflua 120

我使用这样的事实

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

并写了我自己的logexp函数。在终端中运行时ab需要在换行符中输入值和:

\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:我想我可以...现在完成了
Kyle
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.