65.9K
CodeProject 正在变化。 阅读更多。
Home

Polynomial.Net

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.33/5 (9投票s)

2010年5月24日

CPOL

5分钟阅读

viewsIcon

34115

downloadIcon

665

多项式类库 - 轻松处理多项式

PolynomialNet.jpg

引言

多项式:多项式是涉及一个或多个变量的幂之和与系数相乘的数学表达式。

背景

正如多项式定义中所清晰表明的,在将多项式建模为 .NET 类时,我们有一些主要概念。

  1. 术语
  2. TermCollection
  3. Polynomial

Term 表示多项式的一部分,包括变量、Power(幂)和 Coefficients(系数)。
Term 的集合将构成一个多项式表达式。
在用 .NET 技术建模多项式时,我们必须考虑上述概念。因此,我们从 Polynomial 类开始。在本文中,我们将多项式称为抽象词(Poly)。
Poly 类有一个主成员,名为 TermCollectionTermCollection 继承自 CollectionBase 类,它是一个 Term 类的集合。
Term 类有两个属性(PowerCoefficient)和两个构造函数。其中一个 Term 构造函数可以解析 String 表达式中的 PowerCoefficientString 表达式可能如下所示: “x”、“-x^2”、“3x^2”、“-3”……

Poly 类有一个构造函数,类似于 Term 类,用于从 String 表达式解析 Term。这些方法将在本文中进行解释。

Using the Code

为了用简单的词语阐明 Poly 类,我将尝试从底层到顶层解释嵌套类。在我们 Poly 类中使用的嵌套类的最底层是 Term 类。

术语

Term 类在第一个构造函数中接受两个参数,并将它们传递给 PowerCoefficient 属性。此构造函数将在代码中创建 Term 的简单实例时使用,而不是在类客户端中使用。

/// <summary>
/// Simple Constructor which Create a new Instance of Term Class
/// With 2 parameters
///  
/// </summary>
/// <param name="power"></param>
/// <param name="coefficient"></param>
public Term(int power,int coefficient)
{
    this.Power = power;
    this.Coefficient = coefficient;
}

第二个构造函数接受一个 string 表达式,并直接从 string 中解析 Powercoefficient。为了从 string 参数解析属性,会发生以下情况:

字符串 Coefficient(系数) 示例
n n 0 -3
nx n 1 4x
nx^m n m 2x^3
/// <summary>
/// Constructor Overload which Create a new Instance of Term Class
/// With a simple string and try to read the Power and Coefficient
/// by identifying the input string
/// </summary>
/// <param name="TermExpression"></param>
public Term(string TermExpression)
{
    if (TermExpression.Length > 0)
    {
        if (TermExpression.IndexOf("x^") > -1)
        {
            string CoefficientString = 
		TermExpression.Substring(0, TermExpression.IndexOf("x^"));
            int IndexofX = TermExpression.IndexOf("x^");
            string PowerString = TermExpression.Substring
		(IndexofX + 2, (TermExpression.Length -1) - (IndexofX + 1));
            if (CoefficientString == "-")
                this.Coefficient = -1;
            else if (CoefficientString == "+" | CoefficientString == "")
                this.Coefficient = 1;
            else
                this.Coefficient = int.Parse(CoefficientString);
            
            this.Power = int.Parse(PowerString);
        }
        else if (TermExpression.IndexOf("x") > -1)
        {
            this.Power = 1;
            string CoefficientString = TermExpression.Substring
			(0, TermExpression.IndexOf("x"));
            if (CoefficientString == "-")
                this.Coefficient = -1;
            else if (CoefficientString == "+" | CoefficientString == "")
                this.Coefficient = 1;
            else
                this.Coefficient = int.Parse(CoefficientString);
        }
        else
        {
            this.Power = 0;
            this.Coefficient = int.Parse(TermExpression);
        }
    }
    else
    {
        this.Power = 0;
        this.Coefficient = 0;
    }
}

最后,重写 Term 类的 .ToString() 方法将在输出中写入 Termstring 格式。

public override string ToString()
{
    string Result = string.Empty;
    if (Coefficient != 0)
    {
        if (this.Coefficient > 0)
            Result += "+";
        else
            Result += "-";
            
        if (this.Power == 0)
            Result += (this.Coefficient < 0 ? this.Coefficient * -1 : 
		this.Coefficient).ToString();
        else if (this.Power == 1)
            if (this.Coefficient > 1 | this.Coefficient < -1)
                Result += string.Format("{0}x",(this.Coefficient <0 ? 
		this.Coefficient * -1 : this.Coefficient).ToString());
            else
                Result += "x";
        else
            if (this.Coefficient > 1 | this.Coefficient < -1)
                Result += string.Format("{0}x^{1}", 
		(this.Coefficient < 0 ? this.Coefficient * -1 : 
		this.Coefficient).ToString(), this.Power.ToString());
            else
                Result += string.Format("x^{0}",this.Power.ToString());
    }
    return Result;
}

现在我们可以将多项式表达式的 Term 存储在 arrayArrayList 等中……也许自定义的 Collection 类是最佳选择。

TermCollection

TermCollection 是一个继承自 CollectionbaseCollection 类。一些方法从 Collectionbase 中重写,但为了处理获取项,我们必须在 TermCollectionAdd 方法中检查 TermPower。这种格式的多项式不合适:“3x^2+2x^2+x^2”(该表达式实际上是“6x^2”)。

因此,为了防止这些错误,我们必须编写一个方法来在 TermCollection 类的 Add 方法中检查输入值的 Power

/// <summary>
/// Check if there is any Term by the given Power.
/// </summary>
/// <param name="p"></param>
/// <returns></returns>
public bool HasTermByPower(int p)
{
    foreach (Term t in List)
    {
        if (t.Power == p)
            return true;
    }
    return false;
}

AddToEqualPower() 方法会将输入 TermCoefficient 添加到具有相同 Power 的当前 Term 中。

/// <summary>
/// This will Add the Term to the Same Power Term if it's already exists in the Collection.
/// This mean we Plus the New Terms to the Currnet Polynomial
/// </summary>
/// <param name="value"></param>
public void AddToEqualPower(Term value)
{
    foreach (Term t in List)
    {
        if (t.Power == value.Power)
        t.Coefficient += value.Coefficient;
    }
}

最后,我们必须在 TermCollection 类的 Add 方法中调用前面的方法。

/// <summary>
/// Modified Add Method: 
/// First check the Coefficient Value. 
/// this Method checks if there is any Term by the Same Input Power.
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public int Add(Term value)
{
    if (value.Coefficient != 0)
    {
        if (this.HasTermByPower(value.Power))
        {
            this.AddToEqualPower(value);
            return -1;
        }
        else
            return (List.Add(value));
    }
    else
        return -1;
}

注意:系数为零的 Term 不是有效的 Term,因此我们应该阻止将这些 Term 添加到 TermCollection 中。

TermCollection 包含一些附加方法,例如 Sort,用于按 PowerTerm 的顺序进行排序。稍后在 Poly 类中,我们将遍历 TermCollection,使用 Term 类的 .ToString() 方法来编写完整的多项式表达式。因此,对 Term 进行排序将有助于我们以常规样式显示 Term

/// <summary>
/// Array Sort Type
/// Values: ASC , DESC
/// </summary>
public enum SortType
{
    ASC = 0,
    DES = 1
}

/// <summary>
/// Sor Method: Sort Items of Collection in ASC or DESC Order.
/// </summary>
/// <param name="Order">SortOrder values : ASC or DESC</param>
public void Sort(SortType Order)
{
    TermCollection result = new TermCollection();
    if (Order == SortType.ASC)
    {
        while (this.Length > 0)
        {
            Term MinTerm = this[0];
            foreach (Term t in List)
            {
                if (t.Power < MinTerm.Power)
                {
                    MinTerm = t;
                }
            }
            result.Add(MinTerm);
            this.Remove(MinTerm);
        }
    }
    else
    {
        while (this.Length > 0)
        {
            Term MaxTerm = this[0];
            foreach (Term t in List)
            {
                if (t.Power > MaxTerm.Power)
                {
                    MaxTerm = t;
                }
            }
            result.Add(MaxTerm);
            this.Remove(MaxTerm);
        }
    }       
    this.Clear();
    foreach (Term t in result)
    {
        this.Add(t);
    }
}

Poly

Poly 类有一个名为 Terms 的属性,它是一个 TermCollection 类。此属性将存储多项式的项。

Poly 类的第一个构造函数接受一个 TermCollection 参数来创建 Poly 的简单实例。此构造函数仅在代码中使用,而不是在类客户端中使用。

第二个构造函数接受一个包含多项式表达式的 String 表达式。首先,此构造函数使用此 static 方法验证表达式。

/// <summary>
/// Static method which Validate the input Expression
/// </summary>
/// <param name="Expression"></param>
/// <returns></returns>
public static bool ValidateExpression(string Expression)
{
    if (Expression.Length == 0)
        return false;
        
    Expression = Expression.Trim();
    Expression = Expression.Replace(" ", "");
    while (Expression.IndexOf("--") > -1 | Expression.IndexOf("++") > -1 | 
	Expression.IndexOf("^^") > -1 | Expression.IndexOf("xx") > -1)
    {
        Expression = Expression.Replace("--", "-");
        Expression = Expression.Replace("++", "+");
        Expression = Expression.Replace("^^", "^");
        Expression = Expression.Replace("xx", "x");
    }
    string ValidChars = "+-x1234567890^";
    bool result = true;
    foreach (char c in Expression)
    {
        if (ValidChars.IndexOf(c) == -1)
            result = false;
    }
    return result;
        }

多项式表达式中的任何 Term 都将以 **+** 或 **-** 字符结尾。(3x^2 + 2x - 5) 通过遍历多项式表达式的字符可以读取这些项。.ReadPolyExpression() 方法将执行此操作。

/// <summary>
/// Read Method will Identify any Term in the Expression and Create a new Instance of 
/// Term Class and add it to the TermCollection
/// </summary>
/// <param name="PolyExpression">input string of Polynomial Expression</param>
private void ReadPolyExpression(string PolyExpression)
{
    if(ValidateExpression(PolyExpression))
    {
        string NextChar = string.Empty;
        string NextTerm = string.Empty;
        for (int i = 0 ; i < PolyExpression.Length; i++)
        {
            NextChar = PolyExpression.Substring(i, 1);
            if ((NextChar == "-" | NextChar == "+") & i > 0)
            {
                Term TermItem = new Term(NextTerm);
                this.Terms.Add(TermItem);
                NextTerm = string.Empty;
            }
            NextTerm += NextChar;
        }
        Term Item = new Term(NextTerm);
        this.Terms.Add(Item);
        
        this.Terms.Sort(TermCollection.SortType.ASC);
    }
    else
    {
        throw new Exception("Invalid Polynomial Expression");
    }
}

现在我们有了完整的多项式类,但仍需要一些东西。通过创建一种新类型(尤其是数学类型),我们必须查看此新类型的运算符。如果您使用简单的运算符 + 来加 Poly 类的实例,将不会发生任何事情。最佳解决方案是在此新类型(Poly 类)中进行运算符重载。

运算符重载

这是什么意思?当您尝试执行类似以下操作时:

int a = 3 + 4;

实际上,您调用的是此方法:

int.+(int FirstArgument, int SecondArgument) 

类似于

int.+(3,4); 

此方法将返回一个值为 7int 变量。现在,我们要为我们的新类型(Poly 类)创建我们的 + 方法。我们必须在类中重载加号 (+) 运算符。

/// <summary>
/// Plus Operator: 
/// Add Method of TermsCollection will Check the Power of each Term And if it's already 
/// exists in the Collection Just Plus the Coefficient of the Term 
/// and This Mean Plus Operation.
/// So We Simply Add the Terms of Second Poly to the First one.
/// </summary>
/// <param name="p1"></param>
/// <param name="p2"></param>
/// <returns></returns>
public static Poly operator +(Poly p1, Poly p2)
{
    Poly result = new Poly(p1.ToString());
    foreach (Term t in p2.Terms)
        result.Terms.Add(t);
    return result;
}

注意: 当我们对两个 Poly 实例执行加法运算时,我们正在尝试将具有相同 PowersCoefficient 相加。这意味着 "3x^2+4" + "2x^2-2" 将是 "5x^2+2"。我们在 TermCollectionAdd 方法中完成了此操作,因此为了重载 + 运算符,我们只需将第二个 Poly 实例的项添加到第一个实例即可。

下一个运算符是 -。减号 (-) 运算符是将第一个 Poly 实例与第二个 Poly 实例的 **负值** 相加。因此,首先,我们将第二个 Poly 转换为负值,然后将其与第一个相加。

/// <summary>
/// Minus Operations: Like Plus Operation but at first 
/// we just Make the Second Poly to the Negetive Value.
/// </summary>
/// <param name="p1"></param>
/// <param name="p2"></param>
/// <returns></returns>
public static Poly operator -(Poly p1, Poly p2)
{
    Poly result = new Poly(p1.ToString());
    Poly NegetiveP2 = new Poly(p2.ToString());
    foreach (Term t in NegetiveP2.Terms)
        t.Coefficient *= -1;
        
    return result + NegetiveP2;
}

下一个运算符是 Multiple (*)

/// <summary>
/// Multiple Operation: For each term in the First Poly 
/// We Multiple it in the Each Term of Second Poly
/// </summary>
/// <param name="p1"></param>
/// <param name="p2"></param>
/// <returns></returns>
public static Poly operator *(Poly p1, Poly p2)
{
    TermCollection result = new TermCollection();
    int counter = 0;
    foreach (Term t1 in p1.Terms)
    {
        foreach (Term t2 in p2.Terms)
        {
            result.Add(new Term(t1.Power + t2.Power,t1.Coefficient * t2.Coefficient));
            counter++;
        }
    }
    return new Poly(result);
}

下一个是 Divide (/)

/// <summary>
/// 
/// </summary>
/// <param name="p1"></param>
/// <param name="p2"></param>
/// <returns></returns>
public static Poly operator /(Poly p1, Poly p2)
{
    p1.Terms.Sort(TermCollection.SortType.DES);
    p2.Terms.Sort(TermCollection.SortType.DES);
    TermCollection resultTerms = new TermCollection();
    if (p1.Terms[0].Power < p2.Terms[0].Power)
        throw new Exception("Invalid Division: P1.MaxPower is Lower than P2.MaxPower");
    while(p1.Terms[0].Power > p2.Terms[0].Power)
    {
        Term NextResult = new Term(p1.Terms[0].Power - 
	p2.Terms[0].Power, p1.Terms[0].Coefficient / p2.Terms[0].Coefficient);
        resultTerms.Add(NextResult);
        Poly TempPoly = NextResult;
        
        Poly NewPoly = TempPoly * p2;
        p1 = p1 - NewPoly;
    }
    return new Poly(resultTerms);
}

接下来的两个运算符:++ 和 -- 是一类 Plus (+) 运算符。

/// <summary>
/// this will Create a new Poly by the Value of 1 and Plus it to the First Poly.
/// </summary>
/// <param name="p1"></param>
/// <returns></returns>
public static Poly operator ++(Poly p1)
{
    Poly p2 = new Poly("1");
    p1 = p1 + p2;
    return p1;
}

/// <summary>
/// this will Create a new Poly by the Value of -1 and Plus it to the First Poly.
/// </summary>
/// <param name="p1"></param>
/// <returns></returns>
public static Poly operator --(Poly p1)
{
    Poly p2 = new Poly("-1");
    p1 = p1 + p2;
    return p1;
}

重载相等运算符 (=) - 隐式转换

重载 (=) 意味着您正尝试将另一种类型转换为 Poly 类型。这意味着隐式转换。如果您没有重载 (=),类似以下的操作将是语法错误:

Poly myPoly = "4x^2+5x";

通过重载 (=) 运算符,您可以在隐式模式下处理任何类型转换。

/// <summary>
/// Implicit Conversion : this will Convert the single Term to the Poly. 
/// First it Creates a new Instance of TermCollection and Add The Term to it. 
/// Second Creates a new Poly by the TermCollection and Return it.
/// </summary>
/// <param name="t"></param>
/// <returns></returns>
public static implicit operator Poly(Term t)
{
    TermCollection Terms = new TermCollection();
    Terms.Add(t);
    return new Poly(Terms);
}

/// <summary>
/// Implicit Conversion: this will Create new Instance of Poly by the String Constructor
/// And return it.
/// </summary>
/// <param name="expression"></param>
/// <returns></returns>
public static implicit operator Poly(string expression)
{
    return new Poly(expression);
}

/// <summary>
/// Implicit Conversion: this will Create new Instance of Poly by the String Constructor
/// And return it.
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static implicit operator Poly(int value)
{
    return new Poly(value.ToString());
}

最后,.Calculate() 方法将根据 X 的值计算多项式。

关注点

运算符重载是 .NET 技术中最有用的功能。我不知道可以重载运算符,并且处理隐式转换非常有趣。

历史

Polynomial.NET 第一版

Poly Class
Term Class
TermCollection Class
© . All rights reserved.