1 package org.djutils.polynomialroots;
2
3 import org.djutils.complex.Complex;
4
5
6
7
8
9
10
11
12
13
14
15
16 public final class PolynomialRoots
17 {
18
19
20
21 private PolynomialRoots()
22 {
23
24 }
25
26
27
28
29
30
31
32 private static double sign(final double a, final double b)
33 {
34 return b >= 0 ? a : -a;
35 }
36
37
38
39
40
41
42
43
44
45
46
47 public static Complex[] linearRoots(final double q1, final double q0)
48 {
49 if (q1 == 0)
50 {
51 return new Complex[] {};
52 }
53 return linearRoots(q0 / q1);
54 }
55
56
57
58
59
60
61
62
63
64
65 public static Complex[] linearRoots(final double q0)
66 {
67 return new Complex[] { new Complex(-q0, 0) };
68 }
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87 public static Complex[] quadraticRoots(final double q2, final double q1, final double q0)
88 {
89 if (q2 == 0)
90 {
91 return linearRoots(q1, q0);
92 }
93 return quadraticRoots(q1 / q2, q0 / q2);
94 }
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112 public static Complex[] quadraticRoots(final double q1, final double q0)
113 {
114 boolean rescale;
115
116 double a0, a1;
117 double k = 0, x, y, z;
118
119
120 if (q0 == 0.0 && q1 == 0.0)
121 {
122
123 return new Complex[] { Complex.ZERO, Complex.ZERO };
124 }
125 else if (q0 == 0.0)
126 {
127
128
129 Complex nonZeroRoot = new Complex(-q1);
130 return new Complex[] { q1 > 0 ? Complex.ZERO : nonZeroRoot, q1 <= 0 ? nonZeroRoot : Complex.ZERO };
131 }
132 else if (q1 == 0.0)
133 {
134 x = Math.sqrt(Math.abs(q0));
135
136 if (q0 < 0.0)
137 {
138
139 return new Complex[] { new Complex(x, 0), new Complex(-x, 0) };
140 }
141 else
142 {
143
144 return new Complex[] { new Complex(0, x), new Complex(0, -x) };
145 }
146 }
147 else
148 {
149
150
151
152
153 final double sqrtLPN = Math.sqrt(Double.MAX_VALUE);
154 rescale = (q1 > sqrtLPN + sqrtLPN);
155
156 if (!rescale)
157 {
158 x = q1 * 0.5;
159 rescale = (q0 < x * x - Double.MAX_VALUE);
160 }
161
162 if (rescale)
163 {
164 x = Math.abs(q1);
165 y = Math.sqrt(Math.abs(q0));
166
167 if (x > y)
168 {
169 k = x;
170 z = 1.0 / x;
171 a1 = sign(1.0, q1);
172 a0 = (q0 * z) * z;
173 }
174 else
175 {
176 k = y;
177 a1 = q1 / y;
178 a0 = sign(1.0, q0);
179 }
180 }
181 else
182 {
183 a1 = q1;
184 a0 = q0;
185 }
186
187
188 x = a1 * 0.5;
189 y = x * x - a0;
190
191 if (y >= 0.0)
192 {
193
194 y = Math.sqrt(y);
195
196 if (x > 0.0)
197 {
198 y = -x - y;
199 }
200 else
201 {
202 y = -x + y;
203 }
204
205 if (rescale)
206 {
207 y = y * k;
208 z = q0 / y;
209 }
210 else
211 {
212 z = a0 / y;
213 }
214 return new Complex[] { new Complex(Math.max(y, z), 0), new Complex(Math.min(y, z), 0) };
215 }
216 else
217 {
218
219 y = Math.sqrt(-y);
220
221 if (rescale)
222 {
223 x *= k;
224 y *= k;
225 }
226 return new Complex[] { new Complex(-x, y), new Complex(-x, -y) };
227 }
228 }
229 }
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249 public static Complex[] cubicRoots(final double c3, final double c2, final double c1, final double c0)
250 {
251 if (c3 == 0)
252 {
253 return quadraticRoots(c2, c1, c0);
254 }
255 return cubicRoots(c2 / c3, c1 / c3, c0 / c3, false);
256 }
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275 public static Complex[] cubicRoots(final double c2, final double c1, final double c0)
276 {
277 return cubicRoots(c2, c1, c0, false);
278 }
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299 public static Complex[] cubicRoots(final double c2, final double c1, final double c0, final boolean verbose)
300 {
301 final int cubicType;
302 int deflateCase;
303
304 final double macheps = Math.ulp(1.0);
305 final double one27th = 1.0 / 27.0;
306 final double two27th = 2.0 / 27.0;
307 final double third = 1.0 / 3.0;
308
309
310 final double p51 = 8.78558e-1;
311 final double p52 = 1.92823e-1;
312 final double p53 = 1.19748;
313 final double p54 = 3.45219e-1;
314 final double q51 = 5.71888e-1;
315 final double q52 = 5.66324e-1;
316 final double q53 = 2.83772e-1;
317 final double q54 = 4.01231e-1;
318 final double r51 = 7.11154e-1;
319 final double r52 = 5.05734e-1;
320 final double r53 = 8.37476e-1;
321 final double r54 = 2.07216e-1;
322 final double s51 = 3.22313e-1;
323 final double s52 = 2.64881e-1;
324 final double s53 = 3.56228e-1;
325 final double s54 = 4.45532e-3;
326
327 final int allzero = 0;
328 final int linear = 1;
329 final int quadratic = 2;
330 final int general = 3;
331
332 double a0 = 0, a1 = 0, a2 = 0;
333 double a = 0, b = 0, c = 0, k = 0, s = 0, t, u = 0, x = 0, y, z;
334 double xShift = 0;
335
336 if (verbose)
337 {
338 System.out.println("initial cubic c2 = " + c2);
339 System.out.println("initial cubic c1 = " + c1);
340 System.out.println("initial cubic c0 = " + c0);
341 System.out.println("------------------------------------------------");
342 }
343
344
345
346
347
348 if (c0 == 0.0 && c1 == 0.0 && c2 == 0.0)
349 {
350 cubicType = allzero;
351 }
352 else if (c0 == 0.0 && c1 == 0.0)
353 {
354 k = 1.0;
355 a2 = c2;
356 cubicType = linear;
357 }
358 else if (c0 == 0.0)
359 {
360 k = 1.0;
361 a2 = c2;
362 a1 = c1;
363 cubicType = quadratic;
364 }
365 else
366 {
367
368
369
370 x = Math.abs(c2);
371 y = Math.sqrt(Math.abs(c1));
372 z = Math.cbrt(Math.abs(c0));
373 u = Math.max(Math.max(x, y), z);
374
375 if (u == x)
376 {
377 k = 1.0 / x;
378 a2 = sign(1.0, c2);
379 a1 = (c1 * k) * k;
380 a0 = ((c0 * k) * k) * k;
381 }
382 else if (u == y)
383 {
384 k = 1.0 / y;
385 a2 = c2 * k;
386 a1 = sign(1.0, c1);
387 a0 = ((c0 * k) * k) * k;
388 }
389 else
390 {
391 k = 1.0 / z;
392 a2 = c2 * k;
393 a1 = (c1 * k) * k;
394 a0 = sign(1.0, c0);
395 }
396
397 if (verbose)
398 {
399 System.out.println("rescaling factor = " + k);
400 System.out.println("------------------------------------------------");
401 System.out.println("rescaled cubic c2 = " + a2);
402 System.out.println("rescaled cubic c1 = " + a1);
403 System.out.println("rescaled cubic c0 = " + a0);
404 System.out.println("------------------------------------------------");
405 }
406
407 k = 1.0 / k;
408
409 if (a0 == 0.0 && a1 == 0.0 && a2 == 0.0)
410 {
411 cubicType = allzero;
412 }
413 else if (a0 == 0.0 && a1 == 0.0)
414 {
415 cubicType = linear;
416 }
417 else if (a0 == 0.0)
418 {
419 cubicType = quadratic;
420 }
421 else
422 {
423 cubicType = general;
424 }
425 }
426
427 switch (cubicType)
428 {
429 case allzero:
430 return new Complex[] { Complex.ZERO, Complex.ZERO, Complex.ZERO };
431
432 case linear:
433 {
434 double root = -a2 * k;
435 return new Complex[] { new Complex(Math.max(0.0, root), 0), Complex.ZERO, new Complex(Math.min(0.0, root), 0) };
436 }
437
438 case quadratic:
439 {
440 Complex[] otherRoots = quadraticRoots(a2, a1);
441
442 if (otherRoots[0].isReal())
443 {
444
445 double xx = otherRoots[0].re * k;
446 double yy = otherRoots[1].re * k;
447 return new Complex[] { new Complex(Math.max(xx, 0.0), 0), new Complex(Math.max(yy, Math.min(xx, 0.0)), 0),
448 new Complex(Math.min(yy, 0.0), 0) };
449 }
450 else
451 {
452
453 return new Complex[] { Complex.ZERO, otherRoots[0].times(k), otherRoots[1].times(k) };
454 }
455 }
456 case general:
457 {
458
459
460
461
462 final double p1 = 1.09574;
463 final double q1 = 3.23900e-1;
464 final double r1 = 3.23900e-1;
465 final double s1 = 9.57439e-2;
466
467 if (a0 == 1.0)
468 {
469 x = -p1 + q1 * a1 - a2 * (r1 - s1 * a1);
470
471 a = a2;
472 b = a1;
473 c = a0;
474 xShift = 0.0;
475 }
476 else if (a0 == -1.0)
477 {
478 x = p1 - q1 * a1 - a2 * (r1 - s1 * a1);
479
480 a = a2;
481 b = a1;
482 c = a0;
483 xShift = 0.0;
484 }
485 else if (a1 == 1.0)
486 {
487
488 final double q4 = 7.71845e-1;
489 final double s4 = 2.28155e-1;
490
491 if (a0 > 0.0)
492 {
493 x = a0 * (-q4 - s4 * a2);
494 }
495 else
496 {
497 x = a0 * (-q4 + s4 * a2);
498 }
499
500 a = a2;
501 b = a1;
502 c = a0;
503 xShift = 0.0;
504 }
505 else if (a1 == -1.0)
506 {
507
508 final double p3 = 1.14413;
509 final double q3 = 2.75509e-1;
510 final double r3 = 4.45578e-1;
511 final double s3 = 2.59342e-2;
512
513 y = -two27th;
514 y = y * a2;
515 y = y * a2 - third;
516 y = y * a2;
517
518 if (a0 < y)
519 {
520 x = +p3 - q3 * a0 - a2 * (r3 + s3 * a0);
521 }
522 else
523 {
524 x = -p3 - q3 * a0 - a2 * (r3 - s3 * a0);
525 }
526
527 a = a2;
528 b = a1;
529 c = a0;
530 xShift = 0.0;
531 }
532 else if (a2 == 1.0)
533 {
534 b = a1 - third;
535 c = a0 - one27th;
536
537 if (Math.abs(b) < macheps && Math.abs(c) < macheps)
538 {
539 x = -third * k;
540 Complex root = new Complex(x, 0);
541 return new Complex[] { root, root, root };
542 }
543 else
544 {
545 y = third * a1 - two27th;
546
547 if (a1 <= third)
548 {
549 if (a0 > y)
550 {
551 x = -p51 - q51 * a0 + a1 * (r51 - s51 * a0);
552 }
553 else
554 {
555 x = +p52 - q52 * a0 - a1 * (r52 + s52 * a0);
556 }
557 }
558 else if (a0 > y)
559 {
560 x = -p53 - q53 * a0 + a1 * (r53 - s53 * a0);
561 }
562 else
563 {
564 x = +p54 - q54 * a0 - a1 * (r54 + s54 * a0);
565 }
566 }
567 if (Math.abs(b) < 1.e-2 && Math.abs(c) < 1.e-2)
568 {
569 c = -third * b + c;
570 if (Math.abs(c) < macheps)
571 {
572 c = 0.0;
573 }
574 a = 0.0;
575 xShift = third;
576 x = x + xShift;
577 }
578 else
579 {
580 a = a2;
581 b = a1;
582 c = a0;
583 xShift = 0.0;
584 }
585 }
586 else if (a2 == -1.0)
587 {
588 b = a1 - third;
589 c = a0 + one27th;
590
591 if (Math.abs(b) < macheps && Math.abs(c) < macheps)
592 {
593 x = third * k;
594 Complex root = new Complex(x, 0);
595 return new Complex[] { root, root, root };
596 }
597 else
598 {
599 y = two27th - third * a1;
600
601 if (a1 <= third)
602 {
603 if (a0 < y)
604 {
605 x = +p51 - q51 * a0 - a1 * (r51 + s51 * a0);
606 }
607 else
608 {
609 x = -p52 - q52 * a0 + a1 * (r52 - s52 * a0);
610 }
611 }
612 else if (a0 < y)
613 {
614 x = +p53 - q53 * a0 - a1 * (r53 + s53 * a0);
615 }
616 else
617 {
618 x = -p54 - q54 * a0 + a1 * (r54 - s54 * a0);
619 }
620 }
621
622 if (Math.abs(b) < 1.e-2 && Math.abs(c) < 1.e-2)
623 {
624 c = third * b + c;
625 if (Math.abs(c) < macheps)
626 {
627 c = 0.0;
628 }
629 a = 0.0;
630 xShift = -third;
631 x = x + xShift;
632 }
633 else
634 {
635 a = a2;
636 b = a1;
637 c = a0;
638 xShift = 0.0;
639 }
640 }
641
642
643 z = x + a;
644 y = x + z;
645 z = z * x + b;
646 y = y * x + z;
647 z = z * x + c;
648 t = z;
649 x = x - z / y;
650
651 int oscillate = 0;
652 boolean bisection = false;
653 boolean converged = false;
654
655 while ((!converged) && (!bisection))
656 {
657 z = x + a;
658 y = x + z;
659 z = z * x + b;
660 y = y * x + z;
661 z = z * x + c;
662
663 if (z * t < 0.0)
664 {
665 if (z < 0.0)
666 {
667 oscillate = oscillate + 1;
668 s = x;
669 }
670 else
671 {
672 u = x;
673 }
674 t = z;
675 }
676
677 y = z / y;
678 x = x - y;
679
680 bisection = oscillate > 2;
681 converged = Math.abs(y) <= Math.abs(x) * macheps;
682
683 if (verbose)
684 {
685 System.out.println("Newton root = " + x);
686 }
687 }
688
689 if (bisection)
690 {
691 t = u - s;
692 while (Math.abs(t) > Math.abs(x) * macheps)
693 {
694 z = x + a;
695 z = z * x + b;
696 z = z * x + c;
697
698 if (z < 0.0)
699 {
700 s = x;
701 }
702 else
703 {
704 u = x;
705 }
706
707 t = 0.5 * (u - s);
708 x = s + t;
709
710 if (verbose)
711 {
712 System.out.println("Bisection root = " + x);
713 }
714 }
715 }
716
717 if (verbose)
718 {
719 System.out.println("------------------------------------------------");
720 }
721
722 x = x - xShift;
723
724
725
726
727 z = Math.abs(x);
728 s = Math.abs(a2);
729 t = Math.abs(a1);
730 u = Math.abs(a0);
731
732 y = z * Math.max(s, z);
733
734 deflateCase = 1;
735
736 if (y < t)
737 {
738 y = t * z;
739 deflateCase = 2;
740 }
741 else
742 {
743 y = y * z;
744 }
745
746 if (y < u)
747 {
748 deflateCase = 3;
749 }
750
751 y = x * k;
752
753 switch (deflateCase)
754 {
755 case 1:
756 x = 1.0 / y;
757 t = -c0 * x;
758 s = (t - c1) * x;
759 break;
760 case 2:
761 s = c2 + y;
762 t = -c0 / y;
763 break;
764 case 3:
765 s = c2 + y;
766 t = c1 + s * y;
767 break;
768
769 default:
770 throw new RuntimeException("Bad switch; cannot happen");
771 }
772
773 if (verbose)
774 {
775 System.out.println("Residual quadratic q1 = " + s);
776 System.out.println("Residual quadratic q0 = " + t);
777 System.out.println("------------------------------------------------");
778 }
779
780 Complex[] quadraticRoots = quadraticRoots(s, t);
781
782
783 if (quadraticRoots[0].isReal())
784 {
785
786 return new Complex[] { new Complex(Math.max(quadraticRoots[0].re, y), 0),
787 new Complex(Math.max(quadraticRoots[1].re, Math.min(quadraticRoots[0].re, y)), 0),
788 new Complex(Math.min(quadraticRoots[1].re, y), 0) };
789 }
790 else
791 {
792
793 return new Complex[] { new Complex(y, 0), quadraticRoots[0], quadraticRoots[1] };
794 }
795 }
796
797 default:
798 throw new RuntimeException("Bad switch; cannot happen");
799 }
800 }
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825 public static Complex[] quarticRoots(final double q4, final double q3, final double q2, final double q1, final double q0)
826 {
827 if (q4 == 0)
828 {
829 return cubicRoots(q3, q2, q1, q0);
830 }
831 return quarticRoots(q3 / q4, q2 / q4, q1 / q4, q0 / q4);
832 }
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856 public static Complex[] quarticRoots(final double q3, final double q2, final double q1, final double q0)
857 {
858 return quarticRoots(q3, q2, q1, q0, false);
859 }
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886 public static Complex[] quarticRoots(final double q3, final double q2, final double q1, final double q0,
887 final boolean verbose)
888 {
889 int quarticType;
890
891 final int biquadratic = 2;
892 final int cubic = 3;
893 final int general = 4;
894
895 double a0 = 0, a1 = 0, a2, a3 = 0;
896 double a, b, c, d, k, s, t, u = 0, x, y, z;
897
898 final double macheps = Math.ulp(1.0);
899
900 if (verbose)
901 {
902 System.out.println("initial quartic q3 = " + q3);
903 System.out.println("initial quartic q2 = " + q2);
904 System.out.println("initial quartic q1 = " + q1);
905 System.out.println("initial quartic q0 = " + q0);
906 System.out.println("------------------------------------------------");
907 }
908
909
910
911
912 if (q0 == 0.0)
913 {
914 k = 1.0;
915 a3 = q3;
916 a2 = q2;
917 a1 = q1;
918 quarticType = cubic;
919 }
920 else if (q3 == 0.0 && q1 == 0.0)
921 {
922 k = 1.0;
923 a2 = q2;
924 a0 = q0;
925 quarticType = biquadratic;
926 }
927 else
928 {
929
930
931
932
933
934 s = Math.abs(q3);
935 t = Math.sqrt(Math.abs(q2));
936 u = Math.cbrt(Math.abs(q1));
937 x = Math.sqrt(Math.sqrt(Math.abs(q0)));
938 y = Math.max(Math.max(Math.max(s, t), u), x);
939
940 if (y == s)
941 {
942 k = 1.0 / s;
943 a3 = sign(1.0, q3);
944 a2 = (q2 * k) * k;
945 a1 = ((q1 * k) * k) * k;
946 a0 = (((q0 * k) * k) * k) * k;
947 }
948 else if (y == t)
949 {
950 k = 1.0 / t;
951 a3 = q3 * k;
952 a2 = sign(1.0, q2);
953 a1 = ((q1 * k) * k) * k;
954 a0 = (((q0 * k) * k) * k) * k;
955 }
956 else if (y == u)
957 {
958 k = 1.0 / u;
959 a3 = q3 * k;
960 a2 = (q2 * k) * k;
961 a1 = sign(1.0, q1);
962 a0 = (((q0 * k) * k) * k) * k;
963 }
964 else
965 {
966 k = 1.0 / x;
967 a3 = q3 * k;
968 a2 = (q2 * k) * k;
969 a1 = ((q1 * k) * k) * k;
970 a0 = sign(1.0, q0);
971 }
972
973 k = 1.0 / k;
974
975 if (verbose)
976 {
977 System.out.println("rescaling factor = " + k);
978 System.out.println("------------------------------------------------");
979 System.out.println("rescaled quartic q3 = " + a3);
980 System.out.println("rescaled quartic q2 = " + a2);
981 System.out.println("rescaled quartic q1 = " + a1);
982 System.out.println("rescaled quartic q0 = " + a0);
983 System.out.println("------------------------------------------------");
984 }
985
986 if (a0 == 0.0)
987 {
988 quarticType = cubic;
989 }
990 else if (a3 == 0.0 && a1 == 0.0)
991 {
992 quarticType = biquadratic;
993 }
994 else
995 {
996 quarticType = general;
997 }
998 }
999
1000 switch (quarticType)
1001 {
1002 case cubic:
1003 {
1004
1005 Complex[] cubicRoots = cubicRoots(a3, a2, a1, verbose);
1006
1007 if (cubicRoots.length == 3 && cubicRoots[0].isReal() && cubicRoots[1].isReal())
1008 {
1009
1010 x = cubicRoots[0].re * k;
1011 y = cubicRoots[1].re * k;
1012 z = cubicRoots[2].re * k;
1013
1014 return new Complex[] { new Complex(Math.max(x, 0), 0), new Complex(Math.max(y, Math.min(x, 0)), 0),
1015 new Complex(Math.max(z, Math.min(y, 0)), 0), new Complex(Math.min(z, 0), 0) };
1016 }
1017 else
1018 {
1019
1020 if (!cubicRoots[0].isReal())
1021 {
1022 throw new RuntimeException("Cannot happen");
1023 }
1024 x = cubicRoots[0].re * k;
1025
1026 return new Complex[] { new Complex(Math.max(0, x), 0), new Complex(Math.min(0, x), 0), cubicRoots[1],
1027 cubicRoots[2] };
1028 }
1029 }
1030
1031 case biquadratic:
1032 {
1033 Complex[] quadraticRoots = quadraticRoots(q2, q0);
1034 if (quadraticRoots.length == 2 && quadraticRoots[0].isReal() && quadraticRoots[1].isReal())
1035 {
1036 x = quadraticRoots[0].re;
1037 y = quadraticRoots[1].re;
1038
1039 if (y >= 0.0)
1040 {
1041 x = Math.sqrt(x) * k;
1042 y = Math.sqrt(y) * k;
1043 return new Complex[] { new Complex(x, 0), new Complex(y, 0), new Complex(-y, 0), new Complex(-x, 0) };
1044 }
1045 else if (x >= 0.0 && y < 0.0)
1046 {
1047 x = Math.sqrt(x) * k;
1048 y = Math.sqrt(Math.abs(y)) * k;
1049 return new Complex[] { new Complex(x, 0), new Complex(-x, 0), new Complex(0, y), new Complex(0, -y) };
1050 }
1051 else if (x < 0.0)
1052 {
1053 x = Math.sqrt(Math.abs(x)) * k;
1054 y = Math.sqrt(Math.abs(y)) * k;
1055 return new Complex[] { new Complex(0, y), new Complex(0, x), new Complex(0, -x), new Complex(0, -y) };
1056 }
1057 }
1058 else
1059 {
1060
1061
1062 x = quadraticRoots[0].re * 0.5;
1063 y = quadraticRoots[0].im * 0.5;
1064 z = Math.sqrt(x * x + y * y);
1065 y = Math.sqrt(z - x) * k;
1066 x = Math.sqrt(z + x) * k;
1067 return new Complex[] { new Complex(x, y), new Complex(x, -y), new Complex(-x, y), new Complex(-x, -y) };
1068
1069 }
1070 }
1071
1072 case general:
1073 {
1074 int nReal;
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092 x = 0.75 * a3;
1093 y = 0.50 * a2;
1094 z = 0.25 * a1;
1095
1096 if (verbose)
1097 {
1098 System.out.println("dQ(x)/dx cubic c2 = " + x);
1099 System.out.println("dQ(x)/dx cubic c1 = " + y);
1100 System.out.println("dQ(x)/dx cubic c0 = " + z);
1101 System.out.println("------------------------------------------------");
1102 }
1103
1104 Complex[] cubicRoots = cubicRoots(x, y, z);
1105
1106 s = cubicRoots[0].re;
1107 x = s + a3;
1108 x = x * s + a2;
1109 x = x * s + a1;
1110 x = x * s + a0;
1111
1112 y = 1.0;
1113
1114 if (cubicRoots[1].isReal())
1115 {
1116 u = cubicRoots[2].re;
1117 y = u + a3;
1118 y = y * u + a2;
1119 y = y * u + a1;
1120 y = y * u + a0;
1121 }
1122
1123 if (verbose)
1124 {
1125 System.out.println("dQ(x)/dx root s = " + s);
1126 System.out.println("Q(s) = " + x);
1127 System.out.println("dQ(x)/dx root u = " + u);
1128 System.out.println("Q(u) = " + y);
1129 System.out.println("------------------------------------------------");
1130 }
1131
1132 if (x < 0.0 && y < 0.0)
1133 {
1134 if (x < y)
1135 {
1136 if (s < 0.0)
1137 {
1138 x = 1.0 - sign(1.0, a0);
1139 }
1140 else
1141 {
1142 x = 2.0;
1143 }
1144 }
1145 else if (u > 0.0)
1146 {
1147 x = -1.0 + sign(1.0, a0);
1148 }
1149 else
1150 {
1151 x = -2.0;
1152 }
1153
1154 nReal = 1;
1155 }
1156 else if (x < 0.0)
1157 {
1158 if (s < -a3 * 0.25)
1159 {
1160 if (s > 0.0)
1161 {
1162 x = -1.0 + sign(1.0, a0);
1163 }
1164 else
1165 {
1166 x = -2.0;
1167 }
1168 }
1169 else if (s < 0.0)
1170 {
1171 x = 1.0 - sign(1.0, a0);
1172 }
1173 else
1174 {
1175 x = 2.0;
1176 }
1177 nReal = 1;
1178 }
1179 else if (y < 0.0)
1180 {
1181 if (u < -a3 * 0.25)
1182 {
1183 if (u > 0.0)
1184 {
1185 x = -1.0 + sign(1.0, a0);
1186 }
1187 else
1188 {
1189 x = -2.0;
1190 }
1191 }
1192 else if (u < 0.0)
1193 {
1194 x = 1.0 - sign(1.0, a0);
1195 }
1196 else
1197 {
1198 x = 2.0;
1199 }
1200 nReal = 1;
1201 }
1202 else
1203 {
1204 nReal = 0;
1205 }
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215 if (nReal > 0)
1216 {
1217 int oscillate = 0;
1218 boolean bisection = false;
1219 boolean converged = false;
1220 int deflateCase;
1221
1222 while ((!converged) && (!bisection))
1223 {
1224 y = x + a3;
1225 z = x + y;
1226 y = y * x + a2;
1227 z = z * x + y;
1228 y = y * x + a1;
1229 z = z * x + y;
1230 y = y * x + a0;
1231
1232 if (y < 0.0)
1233 {
1234 oscillate = oscillate + 1;
1235 s = x;
1236 }
1237 else
1238 {
1239 u = x;
1240 }
1241
1242 y = y / z;
1243 x = x - y;
1244
1245 bisection = oscillate > 2;
1246 converged = Math.abs(y) <= Math.abs(x) * macheps;
1247
1248 if (verbose)
1249 {
1250 System.out.println("Newton root = " + x);
1251 }
1252 }
1253
1254 if (bisection)
1255 {
1256 t = u - s;
1257 while (Math.abs(t) > Math.abs(x) * macheps)
1258 {
1259 y = x + a3;
1260 y = y * x + a2;
1261 y = y * x + a1;
1262 y = y * x + a0;
1263
1264 if (y < 0.0)
1265 {
1266 s = x;
1267 }
1268 else
1269 {
1270 u = x;
1271 }
1272
1273 t = 0.5 * (u - s);
1274 x = s + t;
1275
1276 if (verbose)
1277 {
1278 System.out.println("Bisection root = " + x);
1279 }
1280 }
1281 }
1282
1283 if (verbose)
1284 {
1285 System.out.println("------------------------------------------------");
1286 }
1287
1288
1289
1290
1291
1292
1293 z = Math.abs(x);
1294 a = Math.abs(a3);
1295 b = Math.abs(a2);
1296 c = Math.abs(a1);
1297 d = Math.abs(a0);
1298
1299 y = z * Math.max(a, z);
1300
1301 deflateCase = 1;
1302
1303 if (y < b)
1304 {
1305 y = b * z;
1306 deflateCase = 2;
1307 }
1308 else
1309 {
1310 y = y * z;
1311 }
1312
1313 if (y < c)
1314 {
1315 y = c * z;
1316 deflateCase = 3;
1317 }
1318 else
1319 {
1320 y = y * z;
1321 }
1322
1323 if (y < d)
1324 {
1325 deflateCase = 4;
1326 }
1327
1328 x = x * k;
1329
1330 switch (deflateCase)
1331 {
1332 case 1:
1333 z = 1.0 / x;
1334 u = -q0 * z;
1335 t = (u - q1) * z;
1336 s = (t - q2) * z;
1337 break;
1338 case 2:
1339 z = 1.0 / x;
1340 u = -q0 * z;
1341 t = (u - q1) * z;
1342 s = q3 + x;
1343 break;
1344 case 3:
1345 s = q3 + x;
1346 t = q2 + s * x;
1347 u = -q0 / x;
1348 break;
1349 case 4:
1350 s = q3 + x;
1351 t = q2 + s * x;
1352 u = q1 + t * x;
1353 break;
1354 default:
1355 throw new RuntimeException("Bad switch; cannot happen");
1356 }
1357
1358 if (verbose)
1359 {
1360 System.out.println("Residual cubic c2 = " + s);
1361 System.out.println("Residual cubic c1 = " + t);
1362 System.out.println("Residual cubic c0 = " + u);
1363 System.out.println("------------------------------------------------");
1364 }
1365
1366 cubicRoots = cubicRoots(s, t, u, verbose);
1367 nReal = 0;
1368 for (Complex complex : cubicRoots)
1369 {
1370 if (complex.isReal())
1371 {
1372 nReal++;
1373 }
1374 }
1375 if (nReal == 3)
1376 {
1377 s = cubicRoots[0].re;
1378 t = cubicRoots[1].re;
1379 u = cubicRoots[2].re;
1380
1381 return new Complex[] { new Complex(Math.max(s, x), 0), new Complex(Math.max(t, Math.min(s, x)), 0),
1382 new Complex(Math.max(u, Math.min(t, x)), 0), new Complex(Math.min(u, x), 0) };
1383 }
1384 else
1385 {
1386 s = cubicRoots[0].re;
1387 return new Complex[] { new Complex(Math.max(s, x), 0), new Complex(Math.min(s, x), 0), cubicRoots[1],
1388 cubicRoots[2] };
1389 }
1390 }
1391 else
1392 {
1393
1394
1395
1396
1397 s = a3 * 0.5;
1398 t = s * s - a2;
1399 u = s * t + a1;
1400
1401 boolean notZero = (Math.abs(u) >= macheps);
1402
1403 if (verbose)
1404 {
1405 System.out.println("dQ/dx (-a3/4) value = " + u);
1406 System.out.println("------------------------------------------------");
1407 }
1408
1409 boolean minimum;
1410 if (a3 != 0.0)
1411 {
1412 s = a1 / a3;
1413 minimum = (a0 > s * s);
1414 }
1415 else
1416 {
1417 minimum = (4 * a0 > a2 * a2);
1418 }
1419
1420 boolean iterate = notZero || (!notZero && minimum);
1421
1422 if (iterate)
1423 {
1424 x = sign(2.0, a3);
1425
1426 int oscillate = 0;
1427 boolean bisection = false;
1428 boolean converged = false;
1429
1430 while (!converged && !bisection)
1431 {
1432 a = x + a3;
1433 b = x + a;
1434 c = x + b;
1435 d = x + c;
1436 a = a * x + a2;
1437 b = b * x + a;
1438 c = c * x + b;
1439 a = a * x + a1;
1440 b = b * x + a;
1441 a = a * x + a0;
1442 y = a * d * d - b * c * d + b * b;
1443 z = 2 * d * (4 * a - b * d - c * c);
1444
1445 if (y > 0.0)
1446 {
1447 oscillate = oscillate + 1;
1448 s = x;
1449 }
1450 else
1451 {
1452 u = x;
1453 }
1454
1455 y = y / z;
1456 x = x - y;
1457
1458 bisection = oscillate > 2;
1459 converged = Math.abs(y) <= Math.abs(x) * macheps;
1460
1461 if (verbose)
1462 {
1463 System.out.println("Newton H(x) root = " + x);
1464 }
1465
1466 }
1467
1468 if (bisection)
1469 {
1470 t = u - s;
1471 while (Math.abs(t) > Math.abs(x * macheps))
1472 {
1473 a = x + a3;
1474 b = x + a;
1475 c = x + b;
1476 d = x + c;
1477 a = a * x + a2;
1478 b = b * x + a;
1479 c = c * x + b;
1480 a = a * x + a1;
1481 b = b * x + a;
1482 a = a * x + a0;
1483 y = a * d * d - b * c * d + b * b;
1484
1485 if (y > 0.0)
1486 {
1487 s = x;
1488 }
1489 else
1490 {
1491 u = x;
1492 }
1493
1494 t = 0.5 * (u - s);
1495 x = s + t;
1496
1497 if (verbose)
1498 {
1499 System.out.println("Bisection H(x) root = " + x);
1500 }
1501
1502 }
1503 }
1504
1505 if (verbose)
1506 {
1507 System.out.println("------------------------------------------------");
1508 }
1509
1510 a = x * k;
1511 b = -0.5 * q3 - a;
1512
1513 x = 4 * a + q3;
1514 y = x + q3 + q3;
1515 y = y * a + q2 + q2;
1516 y = y * a + q1;
1517 y = Math.max(y / x, 0.0);
1518 x = 4 * b + q3;
1519 z = x + q3 + q3;
1520 z = z * b + q2 + q2;
1521 z = z * b + q1;
1522 z = Math.max(z / x, 0.0);
1523 c = a * a;
1524 d = b * b;
1525 s = c + y;
1526 t = d + z;
1527
1528 if (s > t)
1529 {
1530 c = Math.sqrt(y);
1531 d = Math.sqrt(q0 / s - d);
1532 }
1533 else
1534 {
1535 c = Math.sqrt(q0 / t - c);
1536 d = Math.sqrt(z);
1537 }
1538 }
1539 else
1540 {
1541
1542 a = -0.25 * q3;
1543 b = a;
1544
1545 x = a + q3;
1546 x = x * a + q2;
1547 x = x * a + q1;
1548 x = x * a + q0;
1549 y = -0.1875 * q3 * q3 + 0.5 * q2;
1550 z = Math.max(y * y - x, 0.0);
1551 z = Math.sqrt(z);
1552 y = y + sign(z, y);
1553 x = x / y;
1554 c = Math.max(y, 0.0);
1555 d = Math.max(x, 0.0);
1556 c = Math.sqrt(c);
1557 d = Math.sqrt(d);
1558 }
1559
1560 if (a > b)
1561 {
1562 return new Complex[] { new Complex(a, c), new Complex(a, -c), new Complex(b, d), new Complex(b, -d) };
1563 }
1564 else if (a < b)
1565 {
1566 return new Complex[] { new Complex(b, d), new Complex(b, -d), new Complex(a, c), new Complex(a, -c) };
1567 }
1568 else
1569 {
1570 return new Complex[] { new Complex(a, c), new Complex(a, -c), new Complex(a, d), new Complex(a, -d) };
1571 }
1572
1573 }
1574 }
1575
1576 default:
1577 throw new RuntimeException("Bad switch; cannot happen");
1578 }
1579 }
1580 }