Aumenta al potere


12

Sfida

La sfida è scrivere un programma che prende un numero positivoa e un numero diverso da zerob e produce a^b(a elevato alla potenza b). È possibile utilizzare solo + - * / abs()come funzioni / operatori matematici. Questi possono essere applicati solo a valori scalari, ma non a interi elenchi o matrici.

Esempi:

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

Rilevante: http://xkcd.com/217/

Dettagli

È possibile scrivere una funzione o un costrutto simile da utilizzare in console. Se non è possibile utilizzare l'input della console, è possibile supporre che entrambi i numeri vengano salvati in variabili e completati tramite output standard o scrivendo in un file. L'output deve essere corretto per almeno 4 cifre significative. Puoi presumere che entrambi ae bsiano diversi da zero. Un tempo di esecuzione significativamente superiore a 1 minuto non è accettabile. Vincerà il numero minimo di byte. Spiega il tuo programma e il tuo algoritmo.

EDIT: solo le basi positive devono essere considerate. Puoi presumere a>0. Ricorda che entrambi i numeri non devono essere numeri interi !!!


3
Ci stai chiedendo di aumentare a un potere decimale? Come dire, 4.5 ^ 4.5?
fuandon

1
Questo significa che dobbiamo generare anche numeri immaginari se la base è negativa?
Bebe

1
Quale dovrebbe essere l'output -0.5 ** 0.5?
Dennis,

Ok, non ho pensato a quel caso, grazie: le basi negative non devono essere implementate correttamente. @fuandon esattamente, i numeri reali possono avere decimali (almeno nella maggior parte dei linguaggi di programmazione =)
flawr

Vorrei aggiungere un test case con b <0: `4.5 ^ -4.5 = 0.0011496 '
edc65

Risposte:


3

Python, 77

Come per alcune altre risposte, questo si basa su log ed exp. Ma le funzioni sono calcolate risolvendo numericamente equazioni differenziali ordinarie.

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

Soddisfa i requisiti? Per gli esempi nella domanda, sì. Per una grande, ci vorrà molto tempo. Per grandi a o b, diventerà inaccurato.

Esempi:

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

Aggiornamento: flawr ha chiesto maggiori dettagli sulla matematica, quindi eccoti qui. Ho considerato i seguenti problemi di valore iniziale:

  • x '(t) = x (t), con x (0) = 1. La soluzione è exp (t).
  • y '(t) = di (t), con y (0) = 1. La soluzione è exp (bt).

Se riesco a trovare il valore di t tale che x (t) = a, allora avrò y (t) = exp (bt) = a ^ b. Il modo più semplice per risolvere numericamente un problema di valore iniziale è il metodo di Eulero . Si calcola la derivata che la funzione dovrebbe avere e quindi si fa un passo nella direzione della derivata e proporzionale ad essa, ma ridimensionata da una minuscola costante. Quindi è quello che faccio, faccio piccoli passi fino a che x è grande quanto a, e poi vedi cosa è y in quel momento. Bene, è così che ci ho pensato. Nel mio codice, t non viene mai calcolato esplicitamente (è 1e-7 * il numero di passaggi del ciclo while) e ho salvato alcuni caratteri eseguendo i calcoli per x con un invece.


Sembra fantastico, sono felice di vedere un altro approccio diverso! Puoi dirci qualcosa in più su queste equazioni differenziali? So generalmente cosa sono, ma non sono riuscito a capire come li usa il tuo programma =)
flawr

@flawr: OK, ho aggiornato con qualche dettaglio in più sulla matematica.
Riscaldato l'

6

JavaScript (E6) 155 174 191

Modifica 2 Come suggerito da @bebe, utilizzando la funzione ricorsiva (prestazioni peggiori ma più brevi) È stata
leggermente modificata la funzione R per evitare la
suite di test "troppa ricorsione" . La funzione funziona bene per basi <3000 ed esponente nell'intervallo -50..50.
Modifica il golf più e una precisione migliore

Qualsiasi numero reale può essere approssimativo con un numero razionale (e i numeri "reali" standard IEEE memorizzano di fatto i razionali). Qualsiasi numero razionale può essere espresso come una frazione a / b con numeri interi a e b. x ^ (a / b) è la radice b di (x ^ a) o (radice b di x) ^ a. L'esponenziazione dei numeri interi è abbastanza semplice quadrando. La radice intera può essere approssimata usando metodi numerici.

Codice

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

Test nella console FireFox o 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))
}

Ottimo lavoro, non terribilmente preciso ma l'algoritmo è carino =)
flawr

Puoi spiegare cosa e&1&&(r*=b)fa questo , tranne moltiplicare rper b?
Flawr,

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

Grazie, non ero a conoscenza di quell'exploit, ma sembra essere bello per giocare a golf =)
flawr

1
ecco il codice di lavoro: 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))(devo essere stanco)
bebe

6

Haskell, 85 90

Algoritmo exp-log standard. Ora con un nome diverso, rasando qualche altro personaggio:

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]

raiseviene ora chiamato (%), o %in notazione infissa, anche facendo uso consuma meno byte:4.5%(-4.5)

La versione ungolf utilizza anche solo 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)

Esempi:

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

Usa la serie Taylor.
b^x = 1 + ln(b)*x/1! + (ln(b)*x)^2/2! + (ln(b)*x)^3/3! + (ln(b)*x)^4/4! + ...
con approssimazione logaritmica naturale :
ln(b) = (1-1/x) + (1-1/x)^2/2 + (1-1/x)^3/3 + (1-1/x)^4/4 + ...

Ho usato 128 iterazioni per calcolare b^x(più iterazioni sono difficili a causa di fattoriale) e 262144 iterazioni perln(b)


Forse dovresti golf di meno ma aggiungi più precisione: e(80,5) ->1555962210.2240903- dovrebbe essere 3276800000
edc65

@ edc65, hai ragione, fissato per altri 5 caratteri.
Michael M.,

1
È molto bello vedere alcuni approcci diversi!
Flawr

3

golflua 120

Uso il fatto che

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

e ho scritto il mio log& expfunzioni. I valori ae bdevono essere immessi su newline quando vengono eseguiti nel terminale:

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

Esecuzioni campione:

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

Una versione non giocata di 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)

Potete fornire alcuni esempi di output?
flawr

@flawr: suppongo di poter ... e ora fatto
Kyle Kanos il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.