Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there general method to solve for a single unknown if the unknown variable changes?

I have a simple algebraic relationship that uses three variables. I can guarantee that I know two of the three and need to solve for the third, but I don't necessarily know which two of the variables I will know. I'm looking for a single method or algorithm that can handle any of the cases without a huge batch of conditionals. This may not be possible, but I would like to implement it in a more general sense rather than code in every relationship in terms of the other variables. For example, if this were the relationship:

3x - 5y + z = 5

I don't want to code this:

function(int x, int y)
{
  return 5 - 3x + 5y;
}

function(int x, int z)
{
  return (5 - z - 3x)/(-5);
}

And so on. Is there a standard sort of way to handle programming problems like this? Maybe using matrices, parameterization, etc?

like image 407
topher Avatar asked Dec 24 '14 19:12

topher


Video Answer


2 Answers

If you restrict yourself to the kind of linear functions shown above, you could generalize the function like this

3x - 5y + z = 5

would become

a[0]*x[0] + a[1]*x[1] + a[2]*x[2] = c

with a = { 3, -5, 1 } and c = 5.

I.e., you need a list (or array) of constant factors List<double> a; and a list of variables List<double?> x; plus the constant on the right side double c;

public double Solve(IList<double> a, IList<double?> x, double c)
{
    int unknowns = 0;
    int unkonwnIndex = 0; // Initialization required because the compiler is not smart
                          // enough to infer that unknownIndex will be initialized when
                          // our code reaches the return statement.
    double sum = 0.0;

    if (a.Count != x.Count) {
       throw new ArgumentException("a[] and x[] must have same length");
    }
    for (int i = 0; i < a.Count; i++) {
        if (x[i].HasValue) {
           sum += a[i] * x[i].Value;
        } else {
           unknowns++;
           unknownIndex = i;
        }
    }
    if (unknowns != 1) {
       throw new ArgumentException("Exactly one unknown expected");
    }
    return (c - sum) / a[unknownIndex];
}

Example:

3x - 5y + z = 5

    5 - (- 5y + z)
x = --------------
          3

As seen in the example the solution consists of subtracting the sum of all terms except the unknown term from the constant and then to divide by the factor of the unknown. Therefore my solution memorizes the index of the unknown.


You can generalize with powers like this, assuming that you have the equation

a[0]*x[0]^p[0] + a[1]*x[1]^p[1] + a[2]*x[2]^p[2] = c

you need an additional parameter IList<int> p and the result becomes

return Math.Pow((c - sum) / a[unknownIndex], 1.0 / p[unknownIndex]);

as x ^ (1/n) is equal to nth-root(x).


If you use doubles for the powers, you will even be able to represent functions like

         5
7*x^3 + --- + 4*sqrt(z) = 11
        y^2

a = { 7, 5, 4 },  p = { 3, -2, 0.5 },  c = 11

because

          1
x^(-n) = ---
         x^n

and

nth-root(x) = x^(1/n)

However, you will not be able to find the roots of true non-linear polynomials like x^2 - 5x = 7. The algorithm shown above, works only, if the unknown appears exactly once in the equation.

like image 187
Olivier Jacot-Descombes Avatar answered Oct 12 '22 13:10

Olivier Jacot-Descombes


Yes, here is one function:

private double? ValueSolved (int? x, int? y, int? z)
    {
      if (y.HasValue && z.HasValue && !x.HasValue
         return (5 + (5 * y.Value) - z.Value) / 3;

      if (x.HasValue && z.HasValue && !y.HasValue
        return (5 - z.Value - (3 * x.Value)) / -5;

      if (x.HasValue && y.HasValue && !z.HasValue
        return 5 - (3 * x.Value) + (5 * y.Value);

      return null;
     }
like image 2
MikeG Avatar answered Oct 12 '22 13:10

MikeG