힘을 키우다


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?
Dennis

좋아, 나는 그 경우를 생각하지 않았다. @fuandon 정확히, 실수는 소수를 가질 수 있습니다 (적어도 대부분의 프로그래밍 언어에서 =)
flawr

b <0 인 테스트 케이스를 추가하고 싶습니다 :`4.5 ^ -4.5 = 0.0011496 '
edc65 8:14에

답변:


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) = by (t), y (0) = 1입니다. 해는 exp (bt)입니다.

x (t) = a와 같이 t의 값을 찾을 수 있으면 y (t) = exp (bt) = a ^ b가됩니다. 초기 값 문제를 수치 적으로 해결하는 가장 간단한 방법은 Euler의 방법 입니다. 함수가 가져야하는 도함수를 계산 한 다음 , 도함수 의 방향 으로 비례 하여 작지만 일정한 상수로 단계를 밟습니다. 이것이 제가하는 일입니다. x가 a만큼 클 때까지 작은 단계를 밟은 다음 y가 무엇인지 확인하십시오. 그게 내가 생각한 방식이야 내 코드에서 t는 명시 적으로 계산되지 않으며 (1e-7 * while 루프의 단계 수) 대신 x 대신 계산을 수행하여 일부 문자를 저장했습니다.


좋아 보인다, 나는 또 다른 접근법을 보게되어 기쁘다! 이 미분 방정식에 대해 좀 더 말씀해 주시겠습니까? 나는 일반적으로 그들이 무엇인지 알고 있지만 당신이 어떻게 프로그램을 사용하는지 알아낼 수 없었습니다 =)
flawr

@flawr : 좋습니다. 수학에 대한 자세한 내용으로 업데이트했습니다.
재가열

6

자바 스크립트 (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))
}

좋은 일, 굉장히 정확하지는 않지만 알고리즘은 근사하다 =)
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))(내가 피곤이어야 함)
비비

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

Taylor 시리즈를 사용하십시오.
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
다른 접근법을 보는 것이 매우 좋습니다!
flawr

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

ungolfed 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 : 나는 할 수 있다고 생각합니다. 그리고 이제 끝났습니다
Kyle Kanos
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.