Introduction
Polynomials: A polynomial is a mathematical expression involving a sum of powers in one or more variables multiplied by coefficients.
Background
As it’s clear in the definition of Polynomial, we have some main concepts in modelling a polynomial to a .NET class:
Term
TermCollection
Polynomial
class
Term
demonstrates a part of polynomial which includes the variable, Power
and Coefficients
.
A collection of Terms will create a polynomial expression.
In Modelling a Polynomial by .NET Technology, we must consider the concepts above. So we start with Polynomial
class. In this article, we call Polynomial in abstract word (Poly
).
Poly
class has a Primary Member named TermCollection
. TermCollection
inherits from CollectionBase
class and it’s a collection of Term
class.
Term
class has two Properties (Power
, Coefficient
) and two constructors. One of the Term c
onstructors parses the Power
and Coefficient
from a String
Expression. String
Expression may be something like these String
s: “x
”, “-x^2
”, “3x^2
”, “-3
”…
Poly
class has a constructor like Term
class to parse Term
s from a String
Expression. These methods will be explained in this article.
Using the Code
To clarify the Poly
class in simple words, I just try to explain the nested classes from bottom to top. At the last level of nested classes which we are using in our Poly
class, there is Term
class.
Term
Term
class in the first constructor takes two parameters and passes them to the Power
and Coefficient
properties. This constructor will use in case of creating a simple instance of Term
in code not in Class client.
public Term(int power,int coefficient)
{
this.Power = power;
this.Coefficient = coefficient;
}
The second Constructor takes a string
expression and parses the Power
and coefficient
directly from the string
. To parse the properties from string
parameter, these cases will occur:
String | Coefficient | Power | Example |
n | n | 0 | -3 |
nx | n | 1 | 4x |
nx^m | n | m | 2x^3 |
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;
}
}
At last overriding .ToString()
method of Term
class will write the string
format of Term
at output.
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;
}
Now we can store Term
s of a polynomial expression in an array
or ArrayList
or etc… Maybe a custom Collection
class is the best choice.
TermCollection
TermCollection
is a Collection
class that inherits from Collectionbase
. Some methods are overridden from Collectionbase
but to handle taking terms we must check the Power
of Term
in Add
method of Term<code>Collection
. A polynomial by this format is not suitable: “3x^2+2x^2+x^2
” (this expression in fact is “6x^2
”).
So to prevent these mistakes, we have to write a method to check the Power
of input values in Add
method of TermCollection
class.
public bool HasTermByPower(int p)
{
foreach (Term t in List)
{
if (t.Power == p)
return true;
}
return false;
}
AddToEqualPower()
method will Add
the Coefficient
of Input Term
to the Current Term
by the equal Power
.
public void AddToEqualPower(Term value)
{
foreach (Term t in List)
{
if (t.Power == value.Power)
t.Coefficient += value.Coefficient;
}
}
At last, we must call the previous methods in the Add
method of TermCollection
class:
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;
}
Notice: A Term
by the zero Coefficiant
is not a valid Term
so we should prevent adding these Term
s to the TermCollection
.
TermCollection
has some additional methods like Sort
to Sorting the Terms Order by Power. Later in Poly
class, we will navigate the TermCollection
to write the Complete Polynomial Expression using the .ToString()
method of Term
class. So, sorting the Term
s will help us in displaying Term
s to the regular style.
public enum SortType
{
ASC = 0,
DES = 1
}
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
class has a Property named Terms
which is a TermCollection
class. This property will store the terms of Polynomial.
The first constructor of Poly
class takes a TermCollection
parameter to create a simple instance of Poly
. This constructor just used in Code not Class Client.
The second constructor takes a String
expression that contains the Polynomial Expression. First of all, this constructor validates the Expression by this static
method:
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;
}
Any Term
in Polynomial Expression will end up with a + or - Character. (3x^2 + 2x - 5)
Reading these terms is possible by navigating the Chars of the Polynomial Expression. .ReadPolyExpression()
method will do this:
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");
}
}
Now we have the complete class of Polynomials, but still something is needed. By creating a new type (specially a mathematic one), we must take a look to the Operators of this New
Type. If you use simple Operator + to plus to instance of Poly
class, nothing will happen. The best solution is Operator Overloading in this New
Type.
Operator Overloading
What does it mean? When you try to use something like this:
int a = 3 + 4;
In fact, you call this method:
int.+(int FirstArgument, int SecondArgument)
like:
int.+(3,4);
This method will return an int
variable by the value of 7
. Now we want to create our +
method of our New Type (Poly
class). We must override the Plus (+) operator in our class:
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;
}
Notice: When we're going to Plus two Poly
Instances, we are trying to plus the Coefficient
of Equal Powers
. this means we have "3x^2+4" + "2x^2-2" is "5x^2+2"
. We did it in the Add
Method of TermCollection
, so to overload the +
Operator, we just Add
the Terms of Second Poly
Instance to the First one.
Next Operator is - . Minus (-) Operator is Plusing the First Poly
instance by the Negetive
value of the Second Poly
Instance. So at first, we make the second Poly
into the Negetive value and then Plus it by the first one.
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;
}
Next Operator is Multiple
(*):
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);
}
The next one is Divide
(/):
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);
}
Next two operators: ++ and -- are a kind of Plus
(+) operators:
public static Poly operator ++(Poly p1)
{
Poly p2 = new Poly("1");
p1 = p1 + p2;
return p1;
}
public static Poly operator --(Poly p1)
{
Poly p2 = new Poly("-1");
p1 = p1 + p2;
return p1;
}
Overloading Equal Operator (=) - Implicit Conversion:
Overloading (=) means you are trying to convert another type to the Poly
Type. This means Implicit Converstion. If you didn't overload the (=) something like this is a syntax Error:
Poly myPoly = "4x^2+5x";
By Overloading (=) Operator, you can handle any type conversion in implicit mode:
public static implicit operator Poly(Term t)
{
TermCollection Terms = new TermCollection();
Terms.Add(t);
return new Poly(Terms);
}
public static implicit operator Poly(string expression)
{
return new Poly(expression);
}
public static implicit operator Poly(int value)
{
return new Poly(value.ToString());
}
At last a .Calculate()
method will calculate the Polynomial by the value of X
.
Points of Interest
Operator overloading is the most useful feature of the .NET technology. I didn't know that I can Overload the Operators and Handling Implicit Conversion is very interesting.
History
Polynomial.NET first version:
Poly Class
Term Class
TermCollection Class