poly34.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  1. // poly34.cpp : solution of cubic and quartic equation
  2. // (c) Khashin S.I. http://math.ivanovo.ac.ru/dalgebra/Khashin/index.html
  3. // khash2 (at) gmail.com
  4. // Thanks to Alexandr Rakhmanin <rakhmanin (at) gmail.com>
  5. // public domain
  6. //
  7. #include <math.h>
  8. #include "poly34.h" // solution of cubic and quartic equation
  9. #define TwoPi 6.28318530717958648
  10. const btScalar eps = SIMD_EPSILON;
  11. //=============================================================================
  12. // _root3, root3 from http://prografix.narod.ru
  13. //=============================================================================
  14. static SIMD_FORCE_INLINE btScalar _root3(btScalar x)
  15. {
  16. btScalar s = 1.;
  17. while (x < 1.)
  18. {
  19. x *= 8.;
  20. s *= 0.5;
  21. }
  22. while (x > 8.)
  23. {
  24. x *= 0.125;
  25. s *= 2.;
  26. }
  27. btScalar r = 1.5;
  28. r -= 1. / 3. * (r - x / (r * r));
  29. r -= 1. / 3. * (r - x / (r * r));
  30. r -= 1. / 3. * (r - x / (r * r));
  31. r -= 1. / 3. * (r - x / (r * r));
  32. r -= 1. / 3. * (r - x / (r * r));
  33. r -= 1. / 3. * (r - x / (r * r));
  34. return r * s;
  35. }
  36. btScalar SIMD_FORCE_INLINE root3(btScalar x)
  37. {
  38. if (x > 0)
  39. return _root3(x);
  40. else if (x < 0)
  41. return -_root3(-x);
  42. else
  43. return 0.;
  44. }
  45. // x - array of size 2
  46. // return 2: 2 real roots x[0], x[1]
  47. // return 0: pair of complex roots: x[0]i*x[1]
  48. int SolveP2(btScalar* x, btScalar a, btScalar b)
  49. { // solve equation x^2 + a*x + b = 0
  50. btScalar D = 0.25 * a * a - b;
  51. if (D >= 0)
  52. {
  53. D = sqrt(D);
  54. x[0] = -0.5 * a + D;
  55. x[1] = -0.5 * a - D;
  56. return 2;
  57. }
  58. x[0] = -0.5 * a;
  59. x[1] = sqrt(-D);
  60. return 0;
  61. }
  62. //---------------------------------------------------------------------------
  63. // x - array of size 3
  64. // In case 3 real roots: => x[0], x[1], x[2], return 3
  65. // 2 real roots: x[0], x[1], return 2
  66. // 1 real root : x[0], x[1] i*x[2], return 1
  67. int SolveP3(btScalar* x, btScalar a, btScalar b, btScalar c)
  68. { // solve cubic equation x^3 + a*x^2 + b*x + c = 0
  69. btScalar a2 = a * a;
  70. btScalar q = (a2 - 3 * b) / 9;
  71. if (q < 0)
  72. q = eps;
  73. btScalar r = (a * (2 * a2 - 9 * b) + 27 * c) / 54;
  74. // equation x^3 + q*x + r = 0
  75. btScalar r2 = r * r;
  76. btScalar q3 = q * q * q;
  77. btScalar A, B;
  78. if (r2 <= (q3 + eps))
  79. { //<<-- FIXED!
  80. btScalar t = r / sqrt(q3);
  81. if (t < -1)
  82. t = -1;
  83. if (t > 1)
  84. t = 1;
  85. t = acos(t);
  86. a /= 3;
  87. q = -2 * sqrt(q);
  88. x[0] = q * cos(t / 3) - a;
  89. x[1] = q * cos((t + TwoPi) / 3) - a;
  90. x[2] = q * cos((t - TwoPi) / 3) - a;
  91. return (3);
  92. }
  93. else
  94. {
  95. //A =-pow(fabs(r)+sqrt(r2-q3),1./3);
  96. A = -root3(fabs(r) + sqrt(r2 - q3));
  97. if (r < 0)
  98. A = -A;
  99. B = (A == 0 ? 0 : q / A);
  100. a /= 3;
  101. x[0] = (A + B) - a;
  102. x[1] = -0.5 * (A + B) - a;
  103. x[2] = 0.5 * sqrt(3.) * (A - B);
  104. if (fabs(x[2]) < eps)
  105. {
  106. x[2] = x[1];
  107. return (2);
  108. }
  109. return (1);
  110. }
  111. } // SolveP3(btScalar *x,btScalar a,btScalar b,btScalar c) {
  112. //---------------------------------------------------------------------------
  113. // a>=0!
  114. void CSqrt(btScalar x, btScalar y, btScalar& a, btScalar& b) // returns: a+i*s = sqrt(x+i*y)
  115. {
  116. btScalar r = sqrt(x * x + y * y);
  117. if (y == 0)
  118. {
  119. r = sqrt(r);
  120. if (x >= 0)
  121. {
  122. a = r;
  123. b = 0;
  124. }
  125. else
  126. {
  127. a = 0;
  128. b = r;
  129. }
  130. }
  131. else
  132. { // y != 0
  133. a = sqrt(0.5 * (x + r));
  134. b = 0.5 * y / a;
  135. }
  136. }
  137. //---------------------------------------------------------------------------
  138. int SolveP4Bi(btScalar* x, btScalar b, btScalar d) // solve equation x^4 + b*x^2 + d = 0
  139. {
  140. btScalar D = b * b - 4 * d;
  141. if (D >= 0)
  142. {
  143. btScalar sD = sqrt(D);
  144. btScalar x1 = (-b + sD) / 2;
  145. btScalar x2 = (-b - sD) / 2; // x2 <= x1
  146. if (x2 >= 0) // 0 <= x2 <= x1, 4 real roots
  147. {
  148. btScalar sx1 = sqrt(x1);
  149. btScalar sx2 = sqrt(x2);
  150. x[0] = -sx1;
  151. x[1] = sx1;
  152. x[2] = -sx2;
  153. x[3] = sx2;
  154. return 4;
  155. }
  156. if (x1 < 0) // x2 <= x1 < 0, two pair of imaginary roots
  157. {
  158. btScalar sx1 = sqrt(-x1);
  159. btScalar sx2 = sqrt(-x2);
  160. x[0] = 0;
  161. x[1] = sx1;
  162. x[2] = 0;
  163. x[3] = sx2;
  164. return 0;
  165. }
  166. // now x2 < 0 <= x1 , two real roots and one pair of imginary root
  167. btScalar sx1 = sqrt(x1);
  168. btScalar sx2 = sqrt(-x2);
  169. x[0] = -sx1;
  170. x[1] = sx1;
  171. x[2] = 0;
  172. x[3] = sx2;
  173. return 2;
  174. }
  175. else
  176. { // if( D < 0 ), two pair of compex roots
  177. btScalar sD2 = 0.5 * sqrt(-D);
  178. CSqrt(-0.5 * b, sD2, x[0], x[1]);
  179. CSqrt(-0.5 * b, -sD2, x[2], x[3]);
  180. return 0;
  181. } // if( D>=0 )
  182. } // SolveP4Bi(btScalar *x, btScalar b, btScalar d) // solve equation x^4 + b*x^2 d
  183. //---------------------------------------------------------------------------
  184. #define SWAP(a, b) \
  185. { \
  186. t = b; \
  187. b = a; \
  188. a = t; \
  189. }
  190. static void dblSort3(btScalar& a, btScalar& b, btScalar& c) // make: a <= b <= c
  191. {
  192. btScalar t;
  193. if (a > b)
  194. SWAP(a, b); // now a<=b
  195. if (c < b)
  196. {
  197. SWAP(b, c); // now a<=b, b<=c
  198. if (a > b)
  199. SWAP(a, b); // now a<=b
  200. }
  201. }
  202. //---------------------------------------------------------------------------
  203. int SolveP4De(btScalar* x, btScalar b, btScalar c, btScalar d) // solve equation x^4 + b*x^2 + c*x + d
  204. {
  205. //if( c==0 ) return SolveP4Bi(x,b,d); // After that, c!=0
  206. if (fabs(c) < 1e-14 * (fabs(b) + fabs(d)))
  207. return SolveP4Bi(x, b, d); // After that, c!=0
  208. int res3 = SolveP3(x, 2 * b, b * b - 4 * d, -c * c); // solve resolvent
  209. // by Viet theorem: x1*x2*x3=-c*c not equals to 0, so x1!=0, x2!=0, x3!=0
  210. if (res3 > 1) // 3 real roots,
  211. {
  212. dblSort3(x[0], x[1], x[2]); // sort roots to x[0] <= x[1] <= x[2]
  213. // Note: x[0]*x[1]*x[2]= c*c > 0
  214. if (x[0] > 0) // all roots are positive
  215. {
  216. btScalar sz1 = sqrt(x[0]);
  217. btScalar sz2 = sqrt(x[1]);
  218. btScalar sz3 = sqrt(x[2]);
  219. // Note: sz1*sz2*sz3= -c (and not equal to 0)
  220. if (c > 0)
  221. {
  222. x[0] = (-sz1 - sz2 - sz3) / 2;
  223. x[1] = (-sz1 + sz2 + sz3) / 2;
  224. x[2] = (+sz1 - sz2 + sz3) / 2;
  225. x[3] = (+sz1 + sz2 - sz3) / 2;
  226. return 4;
  227. }
  228. // now: c<0
  229. x[0] = (-sz1 - sz2 + sz3) / 2;
  230. x[1] = (-sz1 + sz2 - sz3) / 2;
  231. x[2] = (+sz1 - sz2 - sz3) / 2;
  232. x[3] = (+sz1 + sz2 + sz3) / 2;
  233. return 4;
  234. } // if( x[0] > 0) // all roots are positive
  235. // now x[0] <= x[1] < 0, x[2] > 0
  236. // two pair of comlex roots
  237. btScalar sz1 = sqrt(-x[0]);
  238. btScalar sz2 = sqrt(-x[1]);
  239. btScalar sz3 = sqrt(x[2]);
  240. if (c > 0) // sign = -1
  241. {
  242. x[0] = -sz3 / 2;
  243. x[1] = (sz1 - sz2) / 2; // x[0]i*x[1]
  244. x[2] = sz3 / 2;
  245. x[3] = (-sz1 - sz2) / 2; // x[2]i*x[3]
  246. return 0;
  247. }
  248. // now: c<0 , sign = +1
  249. x[0] = sz3 / 2;
  250. x[1] = (-sz1 + sz2) / 2;
  251. x[2] = -sz3 / 2;
  252. x[3] = (sz1 + sz2) / 2;
  253. return 0;
  254. } // if( res3>1 ) // 3 real roots,
  255. // now resoventa have 1 real and pair of compex roots
  256. // x[0] - real root, and x[0]>0,
  257. // x[1]i*x[2] - complex roots,
  258. // x[0] must be >=0. But one times x[0]=~ 1e-17, so:
  259. if (x[0] < 0)
  260. x[0] = 0;
  261. btScalar sz1 = sqrt(x[0]);
  262. btScalar szr, szi;
  263. CSqrt(x[1], x[2], szr, szi); // (szr+i*szi)^2 = x[1]+i*x[2]
  264. if (c > 0) // sign = -1
  265. {
  266. x[0] = -sz1 / 2 - szr; // 1st real root
  267. x[1] = -sz1 / 2 + szr; // 2nd real root
  268. x[2] = sz1 / 2;
  269. x[3] = szi;
  270. return 2;
  271. }
  272. // now: c<0 , sign = +1
  273. x[0] = sz1 / 2 - szr; // 1st real root
  274. x[1] = sz1 / 2 + szr; // 2nd real root
  275. x[2] = -sz1 / 2;
  276. x[3] = szi;
  277. return 2;
  278. } // SolveP4De(btScalar *x, btScalar b, btScalar c, btScalar d) // solve equation x^4 + b*x^2 + c*x + d
  279. //-----------------------------------------------------------------------------
  280. btScalar N4Step(btScalar x, btScalar a, btScalar b, btScalar c, btScalar d) // one Newton step for x^4 + a*x^3 + b*x^2 + c*x + d
  281. {
  282. btScalar fxs = ((4 * x + 3 * a) * x + 2 * b) * x + c; // f'(x)
  283. if (fxs == 0)
  284. return x; //return 1e99; <<-- FIXED!
  285. btScalar fx = (((x + a) * x + b) * x + c) * x + d; // f(x)
  286. return x - fx / fxs;
  287. }
  288. //-----------------------------------------------------------------------------
  289. // x - array of size 4
  290. // return 4: 4 real roots x[0], x[1], x[2], x[3], possible multiple roots
  291. // return 2: 2 real roots x[0], x[1] and complex x[2]i*x[3],
  292. // return 0: two pair of complex roots: x[0]i*x[1], x[2]i*x[3],
  293. int SolveP4(btScalar* x, btScalar a, btScalar b, btScalar c, btScalar d)
  294. { // solve equation x^4 + a*x^3 + b*x^2 + c*x + d by Dekart-Euler method
  295. // move to a=0:
  296. btScalar d1 = d + 0.25 * a * (0.25 * b * a - 3. / 64 * a * a * a - c);
  297. btScalar c1 = c + 0.5 * a * (0.25 * a * a - b);
  298. btScalar b1 = b - 0.375 * a * a;
  299. int res = SolveP4De(x, b1, c1, d1);
  300. if (res == 4)
  301. {
  302. x[0] -= a / 4;
  303. x[1] -= a / 4;
  304. x[2] -= a / 4;
  305. x[3] -= a / 4;
  306. }
  307. else if (res == 2)
  308. {
  309. x[0] -= a / 4;
  310. x[1] -= a / 4;
  311. x[2] -= a / 4;
  312. }
  313. else
  314. {
  315. x[0] -= a / 4;
  316. x[2] -= a / 4;
  317. }
  318. // one Newton step for each real root:
  319. if (res > 0)
  320. {
  321. x[0] = N4Step(x[0], a, b, c, d);
  322. x[1] = N4Step(x[1], a, b, c, d);
  323. }
  324. if (res > 2)
  325. {
  326. x[2] = N4Step(x[2], a, b, c, d);
  327. x[3] = N4Step(x[3], a, b, c, d);
  328. }
  329. return res;
  330. }
  331. //-----------------------------------------------------------------------------
  332. #define F5(t) (((((t + a) * t + b) * t + c) * t + d) * t + e)
  333. //-----------------------------------------------------------------------------
  334. btScalar SolveP5_1(btScalar a, btScalar b, btScalar c, btScalar d, btScalar e) // return real root of x^5 + a*x^4 + b*x^3 + c*x^2 + d*x + e = 0
  335. {
  336. int cnt;
  337. if (fabs(e) < eps)
  338. return 0;
  339. btScalar brd = fabs(a); // brd - border of real roots
  340. if (fabs(b) > brd)
  341. brd = fabs(b);
  342. if (fabs(c) > brd)
  343. brd = fabs(c);
  344. if (fabs(d) > brd)
  345. brd = fabs(d);
  346. if (fabs(e) > brd)
  347. brd = fabs(e);
  348. brd++; // brd - border of real roots
  349. btScalar x0, f0; // less than root
  350. btScalar x1, f1; // greater than root
  351. btScalar x2, f2, f2s; // next values, f(x2), f'(x2)
  352. btScalar dx = 0;
  353. if (e < 0)
  354. {
  355. x0 = 0;
  356. x1 = brd;
  357. f0 = e;
  358. f1 = F5(x1);
  359. x2 = 0.01 * brd;
  360. } // positive root
  361. else
  362. {
  363. x0 = -brd;
  364. x1 = 0;
  365. f0 = F5(x0);
  366. f1 = e;
  367. x2 = -0.01 * brd;
  368. } // negative root
  369. if (fabs(f0) < eps)
  370. return x0;
  371. if (fabs(f1) < eps)
  372. return x1;
  373. // now x0<x1, f(x0)<0, f(x1)>0
  374. // Firstly 10 bisections
  375. for (cnt = 0; cnt < 10; cnt++)
  376. {
  377. x2 = (x0 + x1) / 2; // next point
  378. //x2 = x0 - f0*(x1 - x0) / (f1 - f0); // next point
  379. f2 = F5(x2); // f(x2)
  380. if (fabs(f2) < eps)
  381. return x2;
  382. if (f2 > 0)
  383. {
  384. x1 = x2;
  385. f1 = f2;
  386. }
  387. else
  388. {
  389. x0 = x2;
  390. f0 = f2;
  391. }
  392. }
  393. // At each step:
  394. // x0<x1, f(x0)<0, f(x1)>0.
  395. // x2 - next value
  396. // we hope that x0 < x2 < x1, but not necessarily
  397. do
  398. {
  399. if (cnt++ > 50)
  400. break;
  401. if (x2 <= x0 || x2 >= x1)
  402. x2 = (x0 + x1) / 2; // now x0 < x2 < x1
  403. f2 = F5(x2); // f(x2)
  404. if (fabs(f2) < eps)
  405. return x2;
  406. if (f2 > 0)
  407. {
  408. x1 = x2;
  409. f1 = f2;
  410. }
  411. else
  412. {
  413. x0 = x2;
  414. f0 = f2;
  415. }
  416. f2s = (((5 * x2 + 4 * a) * x2 + 3 * b) * x2 + 2 * c) * x2 + d; // f'(x2)
  417. if (fabs(f2s) < eps)
  418. {
  419. x2 = 1e99;
  420. continue;
  421. }
  422. dx = f2 / f2s;
  423. x2 -= dx;
  424. } while (fabs(dx) > eps);
  425. return x2;
  426. } // SolveP5_1(btScalar a,btScalar b,btScalar c,btScalar d,btScalar e) // return real root of x^5 + a*x^4 + b*x^3 + c*x^2 + d*x + e = 0
  427. //-----------------------------------------------------------------------------
  428. int SolveP5(btScalar* x, btScalar a, btScalar b, btScalar c, btScalar d, btScalar e) // solve equation x^5 + a*x^4 + b*x^3 + c*x^2 + d*x + e = 0
  429. {
  430. btScalar r = x[0] = SolveP5_1(a, b, c, d, e);
  431. btScalar a1 = a + r, b1 = b + r * a1, c1 = c + r * b1, d1 = d + r * c1;
  432. return 1 + SolveP4(x + 1, a1, b1, c1, d1);
  433. } // SolveP5(btScalar *x,btScalar a,btScalar b,btScalar c,btScalar d,btScalar e) // solve equation x^5 + a*x^4 + b*x^3 + c*x^2 + d*x + e = 0
  434. //-----------------------------------------------------------------------------