View Javadoc
1   package org.opentrafficsim.core.math;
2   
3   import org.djunits.value.ValueRuntimeException;
4   
5   /**
6    * Solvers for simple equations.
7    * <p>
8    * Copyright (c) 2013-2026 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
9    * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
10   * </p>
11   * @author Alexander Verbraeck
12   * @author Peter Knoppers
13   */
14  public final class Solver
15  {
16      /**
17       *
18       */
19      private Solver()
20      {
21          // cannot be instantiated.
22      }
23  
24      /**
25       * Solve quadratic equation <cite>ax<sup>2</sup>+bx+c=0</cite> for <cite>x</cite>. Degenerate case <cite>a == 0</cite> is
26       * allowed.
27       * @param a the coefficient of <cite>x<sup>2</sup></cite>
28       * @param b the coefficient of <cite>x</cite>
29       * @param c intercept
30       * @return array with zero, one, or two elements (depending on the number of solutions of the equation)
31       */
32      public static double[] solve(final double a, final double b, final double c)
33      {
34          if (Math.abs(a) < 1E-8) // rounding errors will yield incorrect solutions if we allow very small a
35          {
36              // Degenerate; linear equation
37              return solve(b, c);
38          }
39          // Quadratic equation
40          double discriminant = b * b - 4 * a * c;
41          if (discriminant < 0)
42          {
43              return new double[0];
44          }
45          if (0 == discriminant)
46          {
47              return new double[] {-b / 2 / a};
48          }
49          discriminant = Math.sqrt(discriminant);
50          return new double[] {(-b + discriminant) / 2 / a, (-b - discriminant) / 2 / a};
51      }
52  
53      /**
54       * Solve a quadratic or linear equation and return the solution that is closest (but not less than) a boundary.
55       * @param lowerBound minimum value of good solution
56       * @param a quadratic coefficient
57       * @param b linear coefficient
58       * @param c value of the quadratic function for x==0
59       * @return the solution that is closest (but not less than) a boundary
60       * @throws ValueRuntimeException if there is no acceptable solution
61       */
62      public static double firstSolutionAfter(final double lowerBound, final double a, final double b, final double c)
63              throws ValueRuntimeException
64      {
65          double[] solutions = solve(a, b, c);
66          if (0 == solutions.length)
67          {
68              throw new ValueRuntimeException("No solutions");
69          }
70          else if (1 == solutions.length)
71          {
72              if (solutions[0] >= lowerBound)
73              {
74                  return solutions[0];
75              }
76              throw new ValueRuntimeException("Only one solution and it is before lowerBound");
77          }
78          // Two solutions
79          if (solutions[0] < lowerBound && solutions[1] < lowerBound)
80          {
81              throw new ValueRuntimeException("Both solutions are before lowerBound");
82          }
83          if (solutions[0] < lowerBound)
84          {
85              return solutions[1];
86          }
87          if (solutions[1] < lowerBound)
88          {
89              return solutions[0];
90          }
91          return Math.min(solutions[0], solutions[1]);
92      }
93  
94      /**
95       * Solve linear equation <cite>ax+b=0</cite> for <cite>x</cite>.
96       * @param a the coefficient of <cite>x</cite>
97       * @param b intercept
98       * @return array with one or zero elements (depending on the number of solutions of the equation). The case where both
99       *         <cite>a</cite> and <cite>b</cite> are zero returns an array of length 0.
100      */
101     public static double[] solve(final double a, final double b)
102     {
103         if (0 == a)
104         {
105             // Degenerate; no solution (or infinitely many solutions)
106             return new double[0];
107         }
108         return new double[] {-b / a};
109     }
110 
111 }