【问题标题】:Is there general method to solve for a single unknown if the unknown variable changes?如果未知变量发生变化,是否有解决单个未知数的通用方法?
【发布时间】:2014-12-24 19:19:39
【问题描述】:

我有一个使用三个变量的简单代数关系。我可以保证我知道三个中的两个并且需要解决第三个,但我不一定知道我会知道哪两个变量。我正在寻找一种方法或算法,它可以在没有大量条件的情况下处理任何情况。这可能是不可能的,但我想在更一般的意义上实现它,而不是根据其他变量在每个关系中编码。 例如,如果这是关系:

3x - 5y + z = 5

我不想写这个:

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

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

等等。有没有一种标准的方法来处理这样的编程问题?也许使用矩阵、参数化等?

【问题讨论】:

    标签: c# algorithm symbolic-math


    【解决方案1】:

    如果你把自己限制在上面显示的那种线性函数,你可以像这样概括这个函数

    3x - 5y + z = 5
    

    会变成

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

    a = { 3, -5, 1 } 和 c = 5。

    即,您需要一个常数因子列表(或数组)List<double> a; 和一个变量列表 List<double?> x; 加上右侧的常数 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];
    }
    

    例子:

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

    如示例中所示,解决方案包括从常数中减去除未知项之外的所有项的总和,然后除以未知项。因此,我的解决方案记住了未知数的索引。


    假设你有方程,你可以用这样的幂来概括

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

    你需要一个额外的参数IList&lt;int&gt; p,结果变成

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

    因为x ^ (1/n) 等于nth-root(x)。


    如果你使用双打来表示幂,你甚至可以表示像这样的函数

             5
    7*x^3 + --- + 4*sqrt(z) = 11
            y^2
    
    a = { 7, 5, 4 },  p = { 3, -2, 0.5 },  c = 11
    

    因为

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

    和

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

    但是,您将无法找到真正的非线性多项式的根,例如 x^2 - 5x = 7。上面显示的算法仅适用于未知数在方程中恰好出现一次的情况。

    【讨论】:

    • +1 正确概括了我的想法。没想到使用列表作为参数
    • 您是使用列表还是数组取决于所需的灵活性。由于两者都实现了IList&lt;T&gt;,我将参数更改为IList&lt;T&gt;
    • 我想这只是一个基本的线性方程根查找器,但它可以根据需要推广到更高的维度,并且不需要基于先前知道哪个是未知数的任何条件分支。想我要实现这个,谢谢!
    • 我认为最后一个if 和下面的return 语句不应该在for 循环内。
    • @NikontheThird:你当然是对的。不知道他们是如何到达那里的。
    【解决方案2】:

    是的,这是一个功能:

    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;
         }
    

    【讨论】:

    • 这是显而易见的方法。我认为这个问题需要更笼统的东西。
    • 是的,我可以像你上面所说的那样暴力破解它,但我认为可能有一种更通用的(算法或分析)方法来解决这样的问题。
    【解决方案3】:

    没有解决此类问题的标准方法。

    在一般情况下,符号数学是由专用库解决的问题,Math.NET 有一个您可能感兴趣的符号库:http://symbolics.mathdotnet.com/

    具有讽刺意味的是,一个更复杂的问题,一个线性方程组的系统,可以通过计算机通过计算逆矩阵来轻松解决。 您可以以这种方式设置提供的方程式,但 .NET 中没有内置的通用 Matrix 类。

    在您的 特定 情况下,您可以使用如下内容:

    public int SolveForVar(int? x, int? y, int? z)
    {
        int unknownCount = 0;
        int currentSum = 0;
    
        if (x.HasValue)
           currentSum += 3 * x.Value;
        else
           unknownCount++;
    
        if (y.HasValue)
           currentSum += -5 * y.Value;
        else
           unknownCount++;
    
        if (z.HasValue)
           currentSum += z.Value;
        else
           unknownCount++;
    
        if (unknownCount > 1)
           throw new ArgumentException("Too Many Unknowns");
    
        return 5 - currentSum;
    }
    
    int correctY = SolveForVar(10, null, 3);
    

    显然,这种方法对于较大的变量计数会变得笨拙,并且如果您需要大量动态数字或复杂的运算则不起作用,但它可以在一定程度上推广。

    【讨论】:

      【解决方案4】:

      我不确定您在寻找什么,因为该问题已标记为 ,但您拥有的示例代码正在生成数值解,而不是符号解。

      如果你想为更一般的情况找到数值解,那么定义一个函数

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

      并将其提供给一般root-finding algorithm 以找到将产生根的未知参数的值。大多数寻根实现允许您在沿问题的未锁定维度搜索根之前将特定函数参数锁定为固定值。

      【讨论】:

        猜你喜欢
        • 2011-05-04
        • 1970-01-01
        • 1970-01-01
        • 2023-03-18
        • 1970-01-01
        • 1970-01-01
        • 2017-02-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多