Home | History | Annotate | Download | only in db_vlvm
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 /* $Id: db_utilities_poly.cpp,v 1.2 2010/09/03 12:00:10 bsouthall Exp $ */
     18 
     19 #include "db_utilities_poly.h"
     20 #include "db_utilities.h"
     21 
     22 
     23 
     24 /*****************************************************************
     25 *    Lean and mean begins here                                   *
     26 *****************************************************************/
     27 
     28 void db_SolveCubic(double *roots,int *nr_roots,double a,double b,double c,double d)
     29 {
     30     double bp,bp2,cp,dp,q,r,srq;
     31     double r2_min_q3,theta,bp_through3,theta_through3;
     32     double cos_theta_through3,sin_theta_through3,min2_cos_theta_plu,min2_cos_theta_min;
     33     double si_r_srq,A;
     34 
     35     /*For nondegenerate cubics with three roots
     36     [24 mult 9 add 2sqrt 1acos 1cos=33flops 4func]
     37     For nondegenerate cubics with one root
     38     [16 mult 6 add 1sqrt 1qbrt=24flops 3func]*/
     39 
     40     if(a==0.0) db_SolveQuadratic(roots,nr_roots,b,c,d);
     41     else
     42     {
     43         bp=b/a;
     44         bp2=bp*bp;
     45         cp=c/a;
     46         dp=d/a;
     47 
     48         q=(bp2-3.0*cp)/9.0;
     49         r=(2.0*bp2*bp-9.0*bp*cp+27.0*dp)/54.0;
     50         r2_min_q3=r*r-q*q*q;
     51         if(r2_min_q3<0.0)
     52         {
     53             *nr_roots=3;
     54             /*q has to be > 0*/
     55             srq=sqrt(q);
     56             theta=acos(db_maxd(-1.0,db_mind(1.0,r/(q*srq))));
     57             bp_through3=bp/3.0;
     58             theta_through3=theta/3.0;
     59             cos_theta_through3=cos(theta_through3);
     60             sin_theta_through3=sqrt(db_maxd(0.0,1.0-cos_theta_through3*cos_theta_through3));
     61 
     62             /*cos(theta_through3+2*pi/3)=cos_theta_through3*cos(2*pi/3)-sin_theta_through3*sin(2*pi/3)
     63             = -0.5*cos_theta_through3-sqrt(3)/2.0*sin_theta_through3
     64             = -0.5*(cos_theta_through3+sqrt(3)*sin_theta_through3)*/
     65             min2_cos_theta_plu=cos_theta_through3+DB_SQRT3*sin_theta_through3;
     66             min2_cos_theta_min=cos_theta_through3-DB_SQRT3*sin_theta_through3;
     67 
     68             roots[0]= -2.0*srq*cos_theta_through3-bp_through3;
     69             roots[1]=srq*min2_cos_theta_plu-bp_through3;
     70             roots[2]=srq*min2_cos_theta_min-bp_through3;
     71         }
     72         else if(r2_min_q3>0.0)
     73         {
     74             *nr_roots=1;
     75             A= -db_sign(r)*db_CubRoot(db_absd(r)+sqrt(r2_min_q3));
     76             bp_through3=bp/3.0;
     77             if(A!=0.0) roots[0]=A+q/A-bp_through3;
     78             else roots[0]= -bp_through3;
     79         }
     80         else
     81         {
     82             *nr_roots=2;
     83             bp_through3=bp/3.0;
     84             /*q has to be >= 0*/
     85             si_r_srq=db_sign(r)*sqrt(q);
     86             /*Single root*/
     87             roots[0]= -2.0*si_r_srq-bp_through3;
     88             /*Double root*/
     89             roots[1]=si_r_srq-bp_through3;
     90         }
     91     }
     92 }
     93 
     94 void db_SolveQuartic(double *roots,int *nr_roots,double a,double b,double c,double d,double e)
     95 {
     96     /*Normalized coefficients*/
     97     double c0,c1,c2,c3;
     98     /*Temporary coefficients*/
     99     double c3through2,c3through4,c3c3through4_min_c2,min4_c0;
    100     double lz,ms,ns,mn,m,n,lz_through2;
    101     /*Cubic polynomial roots, nr of roots and coefficients*/
    102     double c_roots[3];
    103     int nr_c_roots;
    104     double k0,k1;
    105     /*nr additional roots from second quadratic*/
    106     int addroots;
    107 
    108     /*For nondegenerate quartics
    109     [16mult 11add 2sqrt 1cubic 2quadratic=74flops 8funcs]*/
    110 
    111     if(a==0.0) db_SolveCubic(roots,nr_roots,b,c,d,e);
    112     else if(e==0.0)
    113     {
    114         db_SolveCubic(roots,nr_roots,a,b,c,d);
    115         roots[*nr_roots]=0.0;
    116         *nr_roots+=1;
    117     }
    118     else
    119     {
    120         /*Compute normalized coefficients*/
    121         c3=b/a;
    122         c2=c/a;
    123         c1=d/a;
    124         c0=e/a;
    125         /*Compute temporary coefficients*/
    126         c3through2=c3/2.0;
    127         c3through4=c3/4.0;
    128         c3c3through4_min_c2=c3*c3through4-c2;
    129         min4_c0= -4.0*c0;
    130         /*Compute coefficients of cubic*/
    131         k0=min4_c0*c3c3through4_min_c2-c1*c1;
    132         k1=c1*c3+min4_c0;
    133         /*k2= -c2*/
    134         /*k3=1.0*/
    135 
    136         /*Solve it for roots*/
    137         db_SolveCubic(c_roots,&nr_c_roots,1.0,-c2,k1,k0);
    138 
    139         if(nr_c_roots>0)
    140         {
    141             lz=c_roots[0];
    142             lz_through2=lz/2.0;
    143             ms=lz+c3c3through4_min_c2;
    144             ns=lz_through2*lz_through2-c0;
    145             mn=lz*c3through4-c1/2.0;
    146 
    147             if((ms>=0.0)&&(ns>=0.0))
    148             {
    149                 m=sqrt(ms);
    150                 n=sqrt(ns)*db_sign(mn);
    151 
    152                 db_SolveQuadratic(roots,nr_roots,
    153                     1.0,c3through2+m,lz_through2+n);
    154 
    155                 db_SolveQuadratic(&roots[*nr_roots],&addroots,
    156                     1.0,c3through2-m,lz_through2-n);
    157 
    158                 *nr_roots+=addroots;
    159             }
    160             else *nr_roots=0;
    161         }
    162         else *nr_roots=0;
    163     }
    164 }
    165 
    166 void db_SolveQuarticForced(double *roots,int *nr_roots,double a,double b,double c,double d,double e)
    167 {
    168     /*Normalized coefficients*/
    169     double c0,c1,c2,c3;
    170     /*Temporary coefficients*/
    171     double c3through2,c3through4,c3c3through4_min_c2,min4_c0;
    172     double lz,ms,ns,mn,m,n,lz_through2;
    173     /*Cubic polynomial roots, nr of roots and coefficients*/
    174     double c_roots[3];
    175     int nr_c_roots;
    176     double k0,k1;
    177     /*nr additional roots from second quadratic*/
    178     int addroots;
    179 
    180     /*For nondegenerate quartics
    181     [16mult 11add 2sqrt 1cubic 2quadratic=74flops 8funcs]*/
    182 
    183     if(a==0.0) db_SolveCubic(roots,nr_roots,b,c,d,e);
    184     else if(e==0.0)
    185     {
    186         db_SolveCubic(roots,nr_roots,a,b,c,d);
    187         roots[*nr_roots]=0.0;
    188         *nr_roots+=1;
    189     }
    190     else
    191     {
    192         /*Compute normalized coefficients*/
    193         c3=b/a;
    194         c2=c/a;
    195         c1=d/a;
    196         c0=e/a;
    197         /*Compute temporary coefficients*/
    198         c3through2=c3/2.0;
    199         c3through4=c3/4.0;
    200         c3c3through4_min_c2=c3*c3through4-c2;
    201         min4_c0= -4.0*c0;
    202         /*Compute coefficients of cubic*/
    203         k0=min4_c0*c3c3through4_min_c2-c1*c1;
    204         k1=c1*c3+min4_c0;
    205         /*k2= -c2*/
    206         /*k3=1.0*/
    207 
    208         /*Solve it for roots*/
    209         db_SolveCubic(c_roots,&nr_c_roots,1.0,-c2,k1,k0);
    210 
    211         if(nr_c_roots>0)
    212         {
    213             lz=c_roots[0];
    214             lz_through2=lz/2.0;
    215             ms=lz+c3c3through4_min_c2;
    216             ns=lz_through2*lz_through2-c0;
    217             mn=lz*c3through4-c1/2.0;
    218 
    219             if(ms<0.0) ms=0.0;
    220             if(ns<0.0) ns=0.0;
    221 
    222             m=sqrt(ms);
    223             n=sqrt(ns)*db_sign(mn);
    224 
    225             db_SolveQuadratic(roots,nr_roots,
    226                 1.0,c3through2+m,lz_through2+n);
    227 
    228             db_SolveQuadratic(&roots[*nr_roots],&addroots,
    229                 1.0,c3through2-m,lz_through2-n);
    230 
    231             *nr_roots+=addroots;
    232         }
    233         else *nr_roots=0;
    234     }
    235 }
    236