Polynomial.Net






4.33/5 (9投票s)
多项式类库 - 轻松处理多项式

引言
多项式:多项式是涉及一个或多个变量的幂之和与系数相乘的数学表达式。
背景
正如多项式定义中所清晰表明的,在将多项式建模为 .NET 类时,我们有一些主要概念。
术语
TermCollection
Polynomial
类
Term
表示多项式的一部分,包括变量、Power
(幂)和 Coefficients
(系数)。Term
的集合将构成一个多项式表达式。
在用 .NET 技术建模多项式时,我们必须考虑上述概念。因此,我们从 Polynomial
类开始。在本文中,我们将多项式称为抽象词(Poly
)。Poly
类有一个主成员,名为 TermCollection
。TermCollection
继承自 CollectionBase
类,它是一个 Term
类的集合。Term
类有两个属性(Power
、Coefficient
)和两个构造函数。其中一个 Term
构造函数可以解析 String
表达式中的 Power
和 Coefficient
。String
表达式可能如下所示: “x
”、“-x^2
”、“3x^2
”、“-3
”……
Poly
类有一个构造函数,类似于 Term
类,用于从 String
表达式解析 Term
。这些方法将在本文中进行解释。
Using the Code
为了用简单的词语阐明 Poly
类,我将尝试从底层到顶层解释嵌套类。在我们 Poly
类中使用的嵌套类的最底层是 Term
类。
术语
Term
类在第一个构造函数中接受两个参数,并将它们传递给 Power
和 Coefficient
属性。此构造函数将在代码中创建 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
中解析 Power
和 coefficient
。为了从 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()
方法将在输出中写入 Term
的 string
格式。
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
存储在 array
或 ArrayList
等中……也许自定义的 Collection
类是最佳选择。
TermCollection
TermCollection
是一个继承自 Collectionbase
的 Collection
类。一些方法从 Collectionbase
中重写,但为了处理获取项,我们必须在 Term
的 Collection
Add
方法中检查 Term
的 Power
。这种格式的多项式不合适:“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()
方法会将输入 Term
的 Coefficient
添加到具有相同 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
,用于按 Power
对 Term
的顺序进行排序。稍后在 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);
此方法将返回一个值为 7
的 int
变量。现在,我们要为我们的新类型(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
实例执行加法运算时,我们正在尝试将具有相同 Powers
的 Coefficient
相加。这意味着 "3x^2+4" + "2x^2-2"
将是 "5x^2+2"
。我们在 TermCollection
的 Add
方法中完成了此操作,因此为了重载 +
运算符,我们只需将第二个 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