Int32 Cubic( Real x3, Real x2, Real x, Real k, Real roots[3] ) { if( IsZero( x3 ) ) return Quadratic( x2, x, k, roots ); Real a, b, c, d, a2, p, q, p3, s; // Normalize a = x2 / x3; b = x / x3; c = k / x3; // Reduction to a depressed cubic a2 = a * a; p = 1.0f / 3.0f * ( -1.0f / 3.0f * a2 + b ); q = 1.0f / 2.0f * ( 2.0f / 27.0f * a * a2 - 1.0f / 3.0f * a * b + c ); s = 1.0f / 3.0f * a; // Cardano's method p3 = p * p * p; d = q * q + p3; if( IsZero( d ) ) { if( IsZero( q ) ) { roots[0] = -s; return 1; } else { Real u = CubeRoot( -q ); roots[0] = 2.0f * u - s; roots[1] = -u - s; return 2; } } if( d < 0.0f ) { Real phi = 1.0f / 3.0f * ACOS( -q / SQRT( -p3 ) ); Real t = 2.0f * SQRT( -p ); roots[0] = t * COS( phi ) - s; roots[1] = -t * COS( phi + PI / 3.0f ) - s; roots[2] = -t * COS( phi - PI / 3.0f ) - s; return 3; } Real u = CubeRoot( SQRT( d ) + ABS( q ) ); roots[0] = ( q > 0.0f ? - u + p / u : u - p / u ) - s; return 1; }
static double f(double t) { if (t <= 0.008856) return 7.787037037037037037037037037037*t + (16./116.); else return CubeRoot((float) t); // more precisse than return pow(t, 1.0/3.0); }
static double f(double t) { const double Limit = (24.0/116.0) * (24.0/116.0) * (24.0/116.0); if (t <= Limit) return (841.0/108.0) * t + (16.0/116.0); else return CubeRoot((float) t); }
int RootSolver::SolveCubic(float c[4], float s[3]) { int i, num; float sub; float A, B, C; float sq_A, p, q; float cb_p, D; // normal form: x^3 + Ax^2 + Bx + C = 0 A = c[2] / c[3]; B = c[1] / c[3]; C = c[0] / c[3]; // substitute x = y - A/3 to eliminate quadric term: x^3 +px + q = 0 sq_A = A * A; p = 0.33333333333333333333333333333333f * (-0.33333333333333333333333333333333f * sq_A + B); q = 0.5 * (0.074074074074074074074074074074074f * A * sq_A - 0.33333333333333333333333333333333f * A * B + C); // use Cardano's formula cb_p = p * p * p; D = q * q + cb_p; if (MCore::InRange<float>(D, -0.000001f, +0.000001f)) { // one triple solution if (MCore::InRange<float>(q, -0.000001f, +0.000001f)) { s[0] = 0; num = 1; } else // one single and one float solution { float u = CubeRoot(-q); s[0] = 2 * u; s[1] = -u; num = 2; } } else if (D < 0) // Casus irreducibilis: three real solutions { float phi = 0.33333333333333333333333333333333f * Math::ACos(-q / Math::Sqrt(-cb_p)); float t = 2 * Math::Sqrt(-p); s[0] = t * Math::Cos(phi); s[1] = -t * Math::Cos(phi + Math::PI * 0.33333333333333333333333333333333f); s[2] = -t * Math::Cos(phi - Math::PI * 0.33333333333333333333333333333333f); num = 3; } else // one real solution { float sqrt_D = Math::Sqrt(D); float u = CubeRoot(sqrt_D - q); float v = -CubeRoot(sqrt_D + q); s[0] = u + v; num = 1; } // resubstitute sub = 0.33333333333333333333333333333333f * A; for (i=0; i<num; ++i) s[i] -= sub; return num; }