1 // Copyright 2001 Google Inc. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS-IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 // Converted to D:  madric@gmail.com (Vijay Nayar)
16 
17 module s2.util.math.mathutil;
18 
19 import s2.util.math.s2const;
20 
21 import math = std.math;
22 
23 bool realRootsForCubic(
24     in real a,
25     in real b,
26     in real c,
27     out real r1,
28     out real r2,
29     out real r3) {
30   // According to Numerical Recipes (pp. 184-5), what
31   // follows is an arrangement of computations to
32   // compute the roots of a cubic that minimizes
33   // roundoff error (as pointed out by A.J. Glassman).
34 
35   const real a_squared = a * a;
36   const real a_third = a / 3.0;
37   const real b_tripled = 3.0 * b;
38   const real Q = (a_squared - b_tripled) / 9.0;
39   const real R = (2.0 * a_squared * a - 3.0 * a * b_tripled + 27.0 * c) / 54.0;
40 
41   const real R_squared = R * R;
42   const real Q_cubed = Q * Q * Q;
43 
44   if (R_squared < Q_cubed) {
45     const real root_Q = math.sqrt(Q);
46     const real two_pi_third = 2.0 * M_PI / 3.0;
47     const real theta_third = math.acos(R / math.sqrt(Q_cubed)) / 3.0;
48     const real minus_two_root_Q = -2.0 * root_Q;
49 
50     r1 = minus_two_root_Q * math.cos(theta_third) - a_third;
51     r2 = minus_two_root_Q * math.cos(theta_third + two_pi_third) - a_third;
52     r3 = minus_two_root_Q * math.cos(theta_third - two_pi_third) - a_third;
53 
54     return true;
55   }
56 
57   const real A = -math.signbit(R)
58       * math.pow(math.abs(R) + math.sqrt(R_squared - Q_cubed), 1.0 / 3.0L);
59 
60   if (A != 0.0) {  // in which case, B from NR is zero
61     r1 = A + Q / A - a_third;
62     return false;
63   }
64 
65   r1 = r2 = r3 = -a_third;
66   return true;
67 }