2014-11-27 9 views
5

Ho bisogno di risolvere un'equazione cubica (a x^3 + b x^2 + c * x + d = 0) analiticamente e in numeri reali, preferibilmente in puro javascript (no libs). Poiché potrebbero esserci da 1 a 3 radici, penso che una serie di numeri sia un tipo di risultato ragionevole.Funzione per risolvere analiticamente l'equazione cubica

P.S. Fornita la mia soluzione qui sotto, spero che possa essere utile.

+0

Radici complesse come bene? – duffymo

+2

Questa domanda sembra essere fuori tema perché si tratta di chiedere ad altri di fare il tuo lavoro per te. – duffymo

+0

@duffymo: nota che la risposta è dello stesso utente; in effetti sta facendo quel lavoro e postandolo qui, penso che la domanda sia solo una domanda. –

risposta

14

Ecco qui. Include la gestione di casi degenerati. L'algoritmo principale è principalmente da wikipedia article.

function cuberoot(x) { 
    var y = Math.pow(Math.abs(x), 1/3); 
    return x < 0 ? -y : y; 
} 

function solveCubic(a, b, c, d) { 
    if (Math.abs(a) < 1e-8) { // Quadratic case, ax^2+bx+c=0 
     a = b; b = c; c = d; 
     if (Math.abs(a) < 1e-8) { // Linear case, ax+b=0 
      a = b; b = c; 
      if (Math.abs(a) < 1e-8) // Degenerate case 
       return []; 
      return [-b/a]; 
     } 

     var D = b*b - 4*a*c; 
     if (Math.abs(D) < 1e-8) 
      return [-b/(2*a)]; 
     else if (D > 0) 
      return [(-b+Math.sqrt(D))/(2*a), (-b-Math.sqrt(D))/(2*a)]; 
     return []; 
    } 

    // Convert to depressed cubic t^3+pt+q = 0 (subst x = t - b/3a) 
    var p = (3*a*c - b*b)/(3*a*a); 
    var q = (2*b*b*b - 9*a*b*c + 27*a*a*d)/(27*a*a*a); 
    var roots; 

    if (Math.abs(p) < 1e-8) { // p = 0 -> t^3 = -q -> t = -q^1/3 
     roots = [cuberoot(-q)]; 
    } else if (Math.abs(q) < 1e-8) { // q = 0 -> t^3 + pt = 0 -> t(t^2+p)=0 
     roots = [0].concat(p < 0 ? [Math.sqrt(-p), -Math.sqrt(-p)] : []); 
    } else { 
     var D = q*q/4 + p*p*p/27; 
     if (Math.abs(D) < 1e-8) {  // D = 0 -> two roots 
      roots = [-1.5*q/p, 3*q/p]; 
     } else if (D > 0) {    // Only one real root 
      var u = cuberoot(-q/2 - Math.sqrt(D)); 
      roots = [u - p/(3*u)]; 
     } else {      // D < 0, three roots, but needs to use complex numbers/trigonometric solution 
      var u = 2*Math.sqrt(-p/3); 
      var t = Math.acos(3*q/p/u)/3; // D < 0 implies p < 0 and acos argument in [-1..1] 
      var k = 2*Math.PI/3; 
      roots = [u*Math.cos(t), u*Math.cos(t-k), u*Math.cos(t-2*k)]; 
     } 
    } 

    // Convert back from depressed cubic 
    for (var i = 0; i < roots.length; i++) 
     roots[i] -= b/(3*a); 

    return roots; 
} 
+0

Puntelli per la scrittura che, supponendo che funzioni! Potrei suggerire di modificare la domanda; Penso che stia attraendo i downvotes perché sembra richiedere una risposta senza lavoro, quando in realtà stai fornendo la risposta qui e hai fatto il lavoro! –

+0

L'epsilon con hardcoding è una cattiva pratica. –

Problemi correlati