Montez en puissance

12

Défi

Le défi consiste à écrire un programme qui prend un nombre positifa , un nombre non nulb et des sorties a^b(a élevé à la puissance b). Vous ne pouvez utiliser + - * / abs()que des fonctions / opérateurs mathématiques. Celles-ci ne peuvent être appliquées qu'aux valeurs scalaires, mais pas aux listes entières ou aux tableaux.

Exemples:

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

Pertinent: http://xkcd.com/217/

Détails

Vous pouvez écrire une fonction ou une construction similaire à utiliser dans la console. Si vous ne pouvez pas utiliser l'entrée de console, vous pouvez supposer que les deux nombres sont enregistrés dans des variables et des sorties via une sortie standard ou en écrivant dans un fichier. La sortie doit être correcte avec au moins 4 chiffres significatifs. Vous pouvez supposer que les deux aet bsont différents de zéro. Un temps d'exécution de plus de 1 minute n'est pas acceptable. Le moins d'octets gagnera. Veuillez expliquer votre programme et votre algorithme.

EDIT: Seules les bases positives doivent être prises en compte. Vous pouvez supposer a>0. Sachez que les deux nombres ne doivent pas nécessairement être des nombres entiers !!!

flawr
la source
3
Vous nous demandez d'élever à une puissance décimale? Comme disons, 4,5 ^ 4,5?
fuandon
1
Cela signifie-t-il que nous devons également produire des nombres imaginaires si la base est négative?
bebe
1
Quelle devrait être la sortie -0.5 ** 0.5?
Dennis
Ok je n'ai pas pensé à ce cas, merci: les bases négatives ne doivent pas être correctement implémentées. @fuandon exactement, les nombres réels peuvent avoir des décimales (au moins dans la plupart des langages de programmation =)
flawr
Je voudrais ajouter un cas de test avec b <0: `4,5 ^ -4,5 = 0,0011496 '
edc65

Réponses:

3

Python, 77

Comme pour certaines autres réponses, cela est basé sur log et exp. Mais les fonctions sont calculées en résolvant numériquement des équations différentielles ordinaires.

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

Répond-il aux exigences? Pour les exemples de la question, oui. Pour un grand, cela prendra beaucoup de temps. Pour les grands a ou b, cela deviendra inexact.

Exemples:

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

Mise à jour: Flawr a demandé plus de détails sur les mathématiques, alors c'est parti. J'ai considéré les problèmes de valeur initiale suivants:

  • x '(t) = x (t), avec x (0) = 1. La solution est exp (t).
  • y '(t) = par (t), avec y (0) = 1. La solution est exp (bt).

Si je peux trouver la valeur de t telle que x (t) = a, alors j'aurai y (t) = exp (bt) = a ^ b. La méthode la plus simple pour résoudre numériquement un problème de valeur initiale est la méthode d'Euler . Vous calculez la dérivée que la fonction est censée avoir, puis faites un pas dans la direction de la dérivée, et proportionnellement à celle-ci, mais mis à l'échelle par une toute petite constante. Voilà donc ce que je fais, faire de petites étapes jusqu'à ce que x soit aussi grand que a, puis voir ce que y est à ce moment-là. Eh bien, c'est comme ça que je pensais. Dans mon code, t n'est jamais calculé explicitement (c'est 1e-7 * le nombre d'étapes de la boucle while), et j'ai enregistré quelques caractères en faisant les calculs pour x avec a à la place.

réchauffé
la source
Cela a l'air génial, je suis heureux de voir une autre approche différente! Pouvez-vous nous en dire un peu plus sur ces équations différentielles? Je sais généralement ce qu'ils sont mais je n'ai pas pu comprendre comment votre programme les utilise =)
flawr
@flawr: OK, j'ai mis à jour avec plus de détails sur les mathématiques.
réchauffé
6

JavaScript (E6) 155174191

Edit 2 Comme suggéré par @bebe, utilisation de la fonction récursive (moins
bonne mais plus courte) Fonction R légèrement modifiée pour éviter «trop de récursivité»
Suite de tests ajoutée. La fonction fonctionne bien pour les bases <3000 et l'exposant dans la plage -50..50.
Modifier plus de golf et une meilleure précision

Tout nombre réel peut être approximatif avec un nombre rationnel (et les nombres «réels» standard IEEE stockent des rationnels en fait). Tout nombre rationnel peut être exprimé sous la forme d'une fraction a / b avec des entiers a et b. x ^ (a / b) est la racine b de (x ^ a) ou (racine b de x) ^ a. L'exponentiation entière est assez facile en quadrature. La racine entière peut être approximée à l'aide de méthodes numériques.

Code

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

Tester dans la console FireFox ou 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))
}
edc65
la source
Bon travail, pas terriblement précis mais l'algorithme est sympa =)
flawr
Pouvez-vous expliquer ce que cela e&1&&(r*=b)fait, sauf en multipliant rpar b?
flawr
1
@flawrif(e&1 != 0) r *= b
bebe
Merci, je n'étais pas au courant de cet exploit, mais il semble être agréable pour jouer au golf =)
flawr
1
voici le code de travail: 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))(je dois être fatigué)
bebe
6

Haskell, 85 90

Algorithme exp-log standard. Maintenant, avec un nom différent, raser quelques caractères supplémentaires:

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]

raiseest maintenant appelé (%), ou %en notation infixe, faisant même que son utilisation consomme moins d'octets:4.5%(-4.5)

La version non golfée utilise également seulement 172 octets:

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]
TheSpanishInquisition
la source
4

JS (ES6), 103 octets

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)

Exemples :

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

Utilisez la série Taylor.
b^x = 1 + ln(b)*x/1! + (ln(b)*x)^2/2! + (ln(b)*x)^3/3! + (ln(b)*x)^4/4! + ...
avec approximation du logarithme naturel :
ln(b) = (1-1/x) + (1-1/x)^2/2 + (1-1/x)^3/3 + (1-1/x)^4/4 + ...

J'ai utilisé 128 itérations pour calculer b^x(plus d'itérations sont difficiles en raison de factorielles) et 262144 itérations pourln(b)

Michael M.
la source
Vous devriez e(80,5) ->1555962210.2240903peut-être moins
jouer au
@ edc65, vous avez raison, corrigé pour 5 caractères supplémentaires.
Michael M.
1
C'est très agréable de voir différentes approches!
flawr
3

golflua 120

J'utilise le fait que

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

et écrit mes propres log& expfonctions. Les valeurs aet bdoivent être saisies sur des sauts de ligne lors de l'exécution dans le terminal:

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

Exemples de cycles:

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

Une version non golfée de Lua est,

-- 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)
Kyle Kanos
la source
Pouvez-vous fournir des exemples de résultats?
flawr
@flawr: Je suppose que je peux ... et maintenant c'est fait
Kyle Kanos