Метод Ейлера

Вступ

 

Бурхливий розвиток обчислювальної техніки висунуло на передній план при вирішенні практичних інженерних і наукових задач обчислювальну  математику і програмування.

Обчислювальна математика вивчає побудову та дослідження чисельних  методів розв'язання математичних задач  за допомогою реалізації відповідних  математичних моделей.

Програмування забезпечує технічну реалізацію їх.

Узагальнену схему  математичного моделювання можна  представити таким чином:

При реалізації даного циклу вимагають  пильної уваги всі його компоненти. Заключним його етапом є отримання  чисельного результату і зіставлення  його з цільовою установкою і, як правило, для досягнення бажаного, або прийнятного  результату, завжди виникає необхідність зміни або математичної моделі, або  обчислювального методу, або алгоритму, або програми.

Слід підкреслити важливість і таких етапів даної технології вирішення задач на ЕОМ як проведення розрахунків і аналіз результатів. (А саме, підготовка вихідних даних, обгрунтування вибору обчислювального  методу, коректність і точність рішення). Важливим моментом є також економічність  вибору: способу розв'язання задачі, чисельного методу, моделі ЕОМ, обчислювальної середовища.

Метод Ейлера з перерахунком

При такому підході рекуррентнеспіввідношення (14) змінюеться, а саме, замістьf(xi, yi) беруть середне арифметичне міжf(xi, yi) таf(xi+1, yi+1).

Тоді

   (15)

Це неявна схема. Вона реалізується у дві ітерації: спочатку знаходиться  перше наближення по (14), вважаючиyi початковою

,     (16)

тоді (16) підставляється в праву частину (15) замістьyi+1

   (17)

Геометрична інтерпретація  методу:

За допомогою методу Ейлера з перерахунком можна робити контроль точності, порівнюючи yi+1 таỹi+1.

На підставі цього можна  вибирати крок. Якщо величина |ỹi+1 – yi+1| порівнянна із заданою точністюe, то крок можна збільшувати, якщо більше, то зменшувати, т.д. має місце схема подвійного прорахунку з оцінкою похибки за величиною

»
,

де y(xi) – точне рішення в точціх = xi, а yiіy*iнаближені значення, отримані з крокомh таh/2 відповідно

Вклад у науку

 

            Ейлер залишив найважливіші праці з самим різним галузям математики, механіки, фізики, астрономії і по ряду прикладних наук. З точки зору математики, XVIII століття - це століття Ейлера. Якщо до нього досягнення в галузі математики були розрізнені і не завжди узгоджені, то Ейлер вперше пов'язав аналіз, алгебру, тригонометрію, теорію чисел та ін дисципліни в єдину систему, і додав чимало власних відкриттів. Значна частина математики викладається з тих пір "по Ейлера".

  формула Ейлера

            Завдяки Ейлера в математику увійшли загальна теорія рядів, дивовижна за красою "формула Ейлера", операція порівняння з цілої модулю, повна теорія безперервних дробів, аналітичний фундамент механіки, численні прийоми інтегрування і рішення диференціальних рівнянь, число e, позначення i для уявної одиниці, гамма - функція з її оточенням і багато іншого.

            По суті саме він створив кілька нових математичних дисциплін - теорію чисел, варіаційне числення, теорію комплексних функцій, диференціальну геометрію поверхонь, спеціальні функції. Інші області його праць: Діофантом аналіз, астрономія, оптика, акустика, статистика і т. д. Пізнання Ейлера були енциклопедичні; крім математики, він глибоко вивчав ботаніку, медицину, хімію, теорію музики, безліч європейських і стародавніх мов.

            Біографи відзначають, що Ейлер був віртуозним алгорітмістом. Він незмінно намагався довести свої відкриття до рівня конкретних обчислювальних методів.

Метод Ейлера із застосуванням наступною ітераційною обробкою.

Метод Эйлера можно ще більше вточнити, застосовуючи ітерационную обробку кожного отриманого значенняyi. А саме, спочатку виходячи з першого грубого наближення по

,                                                                                   (16)     

будують ітераційний процес згідно (15) за такою схемою

.                                                             (18)

Ітерації продовжують  до тих пір, поки в двох послідовних  наближеннях  , не співпадуть відповідні десяткові знаки і вважаютьyi+1» . Як правило, при достатньо невеликому кроціh, ітерації швидко збігаються. Якщо після трьох-четирьох ітерацій не відбулося співпадіння потрібного числа десяткових знаків, то крок розрахунківhзменшується. Після такої обробки значенняyi переходять до наступного вузлуxi+1.

Приклад. По методу Ейлера скласти таблицю рішення на відрізку [0;1] для рівняння з початковою умовоюy(0) = 1, обравши крокh= 0,2.

Результати обчислень  помістимо в таблицю, яка заповнюється наступним чином:

i

xi

yi

Dyi

Точніше у =

0

0

1,0000

0,2000

1,0000

1

0,2

1,2000

0,1733

1,1832

2

0,4

1,3733

0,1561

1,3416

3

0,6

1,5294

0,1492

1,4832

4

0,8

1,6786

0,1451

1,6124

5

1,0

1,8237

 

1,7320


 

У першому рядку приi= 0 записуєтьсяx0 = 0, y0 = 1,000 по ним вираховуєтьсяf(x0, y0) = 1, а післяDy0 = hf(x0, y0) = 0,2. Тоді по формулі (14) виходитьy1 = 1 + 0,2 = 1,2.

Значення x1 = 0,2 іy1 = 1,2000 записуються в другій строчці при i= 1. Використовучи це можна вирахувати

f(x1,y1) = 0,8667; Dy1 = hf(x1,y1) = 0,2×0,8667 = 0,1733.

Тодіy2 = y1 + Dy1 = 1,2 + 0,1733 = 1,3733.

При i = 2,3,4,5 обчислення ведуться аналогічно. В останньому стовпчику таблиці для порівняння поміщені значення точного рішення.

З таблиці видно, що абсолютна  похибка дляy5 складае , що складае 5%.

Зауваження. Метод Ейлера легко поширюється на системи диференціальних рівнянь і на ДУ вищих порядків при їх попередньому приведення до систем ДУ першого порядку.

Розглянемо систему двох рівнянь першого порядку

                                              (19)

З початковими умовамиy(x0) = y0 іz(x0) = z0.

Тоті наближене значення y(xi) »yiтаz(xi) »zi вираховується по формулам

                       (20)

Приклад. Використовуючи метод Ейлера, скласти на відрізку [1;1,5] таблицю значень рішення рівнянь.

                                                       (21)

З початковими умовамиy(1) = 0,77 іy'(1) = –0,44, обравши крокh= 0,1.

Рішення.  Замінимо рівняння (21) за допомогою підстановки y' = z, y" =z'системою рівнянь першого порядку

      

З початковими умовамиy(1) = 0,77 таz(1) = –0,44. Таким чином, маємо

      

Результати обчислення за формулами (20) записані в таблиці

i

xi

yi

DYi

f1=  zi

Dzi

0

1

2

3

4

5

1,0

1,1

1,2

1,3

1,4

1,5

0,77

0,726

0,679

0,629

0,576

0,521

–0,044

–0,047

–0,050

–0,053

–0,055

–0,44

–0,473

–0,503

–0,529

–0,551

–0,033

–0,030

–0,026

–0,022

–0,33

–0,296

–0,260

–0,222


 

Таблиця заповнюється наступним  чином. Записуємо в першому рядкуi= 0, x0=1,0; y0 = 0,77; z0 = –0,44.

Далізнаходим

Використовуючи формули (20) отримуемо

Таким чином, у другому рядку таблиці ми можемо записатиi= 1; x1 = 1,1; y1 = 0,726; z1 = –0,473. За цим значенням знаходимо

Отже,

Заповнення таблиці при i =2, 3, 4, 5 виробляються аналогічно.

 

 

 

 

 

 

 

 

ДОДАТОК

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Linq;

using System.Text;

using System.Windows.Forms;

using System.Collections;

 

namespace Eilar_Metod

{

 

publicpartialclassForm1 : Form

    {

//double y_ = 0;

//double yi = 0;

int n = 5;

int i = 0;

double H;

double Eps = 0.000001;

ExpressionParser F = newExpressionParser();

Hashtable xy = newHashtable();

string Func = "";

public Form1()

        {

            InitializeComponent();

 

        }

privatedouble f(double x, double y)

        {

            xy.Clear();

            xy.Add("x", x.ToString());

            xy.Add("y", y.ToString());

return F.Parse(textBox1.Text, xy);

        }

privatevoid Euler(double yi,double xi,double h)

        {

double fxy = 0;//f(xi,yi)

double y_ = 0; double yi_ = 0; //double ytemp = 0;

            fxy = f(xi, yi);

            y_ = yi + h * fxy;

while(true)

            {

                yi_ = yi + h / 2 * (fxy + f(xi + h, y_));

if (Math.Abs(y_ - yi_) <= Eps) break;

                y_ = yi_;

 

            }

            richTextBox1.Text += "\ny(" +i+")= "+y_;

if (i < n) { i++; Euler(y_, xi + h, h); }

        }

privatevoid button1_Click(object sender, EventArgs e)

        {

try

            {

                i = 0;

                n = (int)numericUpDown1.Value;

                H = Convert.ToDouble(textBox4.Text);

                Func = textBox1.Text;

                Eps = Math.Pow(10, (double)numericUpDown2.Value * (-1));

                richTextBox1.Text = "";

                Euler(Convert.ToDouble(F.Parse(textBox3.Text, xy)), Convert.ToDouble(F.Parse(textBox2.Text, xy)), H);

           }

catch (Exception ex) { MessageBox.Show(ex.Message); }

        }

 

privatevoid linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)

        {

            System.Diagnostics.Process.Start("http://ru.wikipedia.org/wiki/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%AD%D0%B9%D0%BB%D0%B5%D1%80%D0%B0");

        }

 

privatevoid textBox4_TextChanged(object sender, EventArgs e)

        {

try

            {

                H=Convert.ToDouble(textBox4.Text);

if (H >= 1) textBox4.Text = "";

            }

catch { textBox4.Text = "";}

        }

 

 

    }

publicclassExpressionParser

    {

 

privateHashtable ops, trees, htbl, spconst;

privateint maxoplength;

privateint sb_init;

 

///<summary>

/// Default constructor, creates an ExpressionParser object

///</summary>

public ExpressionParser()

        {

            ops = newHashtable(52); // Holds operators

            spconst = newHashtable(12); // Holds constants

            trees = newHashtable(101); // Holds Node tree datastructures

 

// Add all valid operators.

// new Operator( operator, arguments, precedence )

//

// To add a new operator to the parser three things need to be added:

//

// 1. A new line below specifying the operator symbol, the number of

// arguments (in this parser max two arguments!) and the operator precedence.

//

// 2. Change the maxoplength below (if needed) to hold the number of characters

// an operator symbol length can be.

//

// 3. Add the code to evaluate the operator inside the toValue method using the

// same recursive calls as for the other operators.

//

            ops.Add("^", newOperator("^", 2, 3));

            ops.Add("+", newOperator("+", 2, 6));

            ops.Add("-", newOperator("-", 2, 6));

            ops.Add("/", newOperator("/", 2, 4));

            ops.Add("*", newOperator("*", 2, 4));

            ops.Add("cos", newOperator("cos", 1, 2));

            ops.Add("sin", newOperator("sin", 1, 2));

            ops.Add("exp", newOperator("exp", 1, 2));

            ops.Add("ln", newOperator("ln", 1, 2));

            ops.Add("tan", newOperator("tan", 1, 2));

            ops.Add("acos", newOperator("acos", 1, 2));

            ops.Add("asin", newOperator("asin", 1, 2));

            ops.Add("atan", newOperator("atan", 1, 2));

            ops.Add("cosh", newOperator("cosh", 1, 2));

            ops.Add("sinh", newOperator("sinh", 1, 2));

            ops.Add("tanh", newOperator("tanh", 1, 2));

            ops.Add("sqrt", newOperator("sqrt", 1, 2));

            ops.Add("cotan", newOperator("cotan", 1, 2));

            ops.Add("fpart", newOperator("fpart", 1, 2));

            ops.Add("acotan", newOperator("acotan", 1, 2));

            ops.Add("round", newOperator("round", 1, 2));

            ops.Add("ceil", newOperator("ceil", 1, 2));

            ops.Add("floor", newOperator("floor", 1, 2));

            ops.Add("fac", newOperator("fac", 1, 2));

            ops.Add("sfac", newOperator("sfac", 1, 2));

            ops.Add("abs", newOperator("abs", 1, 2));

            ops.Add("log", newOperator("log", 2, 5));

            ops.Add("%", newOperator("%", 2, 4));

            ops.Add(">", newOperator(">", 2, 7));

            ops.Add("<", newOperator("<", 2, 7));

            ops.Add("&&", newOperator("&&", 2, 8));

            ops.Add("==", newOperator("==", 2, 7));

            ops.Add("!=", newOperator("!=", 2, 7));

            ops.Add("||", newOperator("||", 2, 9));

            ops.Add("!", newOperator("!", 1, 1));

            ops.Add(">=", newOperator(">=", 2, 7));

            ops.Add("<=", newOperator("<=", 2, 7));

 

// Constants

            spconst.Add("euler", Math.E);

            spconst.Add("pi", Math.PI);

            spconst.Add("nan", double.NaN);

            spconst.Add("infinity", double.PositiveInfinity);

            spconst.Add("true", 1D);

            spconst.Add("false", 0D);

 

// maximum operator length, used when parsing.

            maxoplength = 6;

 

// init all StringBuilders with this value.

// this will be set to the length of the expression being evaluated by Parse.

            sb_init = 50;

        }

 

 

 

///<summary>Matches all paranthesis and returns true if they all match or false if they do not.</summary>

///<param name="exp">expression to check, infix notation</param>

///<returns>true if ok false otherwise</returns>

privatebool

        matchParant(String exp)

        {

int count = 0;

int i = 0;

 

int l = exp.Length;

 

for (i = 0; i < l; i++)

            {

if (exp[i] == '(')

                {

                    count++;

                }

elseif (exp[i] == ')')

                {

                    count--;

                }

            }

 

return (count == 0);

        }

 

 

 

///<summary>Checks if the character is alphabetic.</summary>

///<param name="ch">Character to check</param>

///<returns>true or false</returns>

privatebool

        isAlpha(char ch)

        {

return ((ch >= 'a'&& ch <= 'z') || (ch >= 'A'&& ch <= 'Z'));

        }

 

 

 

///<summary>Checks if the string can be considered to be a valid variable name.</summary>

///<param name="str">The String to check</param>

///<returns>true or false</returns>

privatebool

        isVariable(String str)

        {

int i = 0;

int len = str.Length;

 

if (isAllNumbers(str)) returnfalse;

 

for (i = 0; i < len; i++)

            {

if (getOp(str, i) != null || isAllowedSym(str[i]))

                {

returnfalse;

                }

            }

 

returntrue;

        }

 

 

///<summary>Checks if the character is a digit</summary>

///<param name="ch">Character to check</param>

///<returns>true or false</returns>

privatebool

        isConstant(char ch)

        {

return (Char.IsDigit(ch));

        }

 

 

 

///<summary>Checks to se if a string is numeric</summary>

///<param name="exp">String to check</param>

///<returns>true if the string was numeric, false otherwise</returns>

privatebool

        isConstant(String exp)

        {

double val = 0D;

bool ok = Double.TryParse(exp, out val);

return (ok && !Double.IsNaN(val));

 

/*try

            { 

                if( Double.IsNaN( Double.Parse( exp ) ) )

                {

                    return false;

                }

            }

            catch

            {

                return false;

            }

 

          return true;*/

        }

 

 

 

///<summary>

/// Checks to see if this String consists of only digits and punctuation.

///</summary>

///<remarks>

/// NOTE: needed in .NET at all ? This is a legacy from the Java version

/// where it was needed because some older JVM's accepted strings that started

/// with digits as numeric when the isConstant method was used.

///</remarks>

///<param name="str">The string to check</param>

///<returns>true if the string was numeric, false otherwise.</returns>

privatebool

        isAllNumbers(String str)

        {

char ch;

int i = 0, l = 0;

bool dot = false;

 

            ch = str[0];

 

if (ch == '-' || ch == '+') i = 1;

 

            l = str.Length;

 

while (i < l)

            {

                ch = str[i];

 

if (!(Char.IsDigit(ch) || ((ch == '.' || ch == ',') && !dot)))

                {

returnfalse;

                }

 

                dot = (ch == '.' || ch == ',');

 

                i++;

            }

 

returntrue;

        }

 

 

 

///<summary>

/// Checks to see if the string is the name of a acceptable operator.

///</summary>

///<param name="str">The string to check</param>

///<returns>true if it is an acceptable operator, false otherwise.</returns>

privatebool

        isOperator(String str)

        {

return (ops.ContainsKey(str));

        }

 

 

 

///<summary>

/// Checks to see if the operator name represented by str takes two arguments.

///</summary>

///<param name="str">The string to check</param>

///<returns>true if the operator takes two arguments, false otherwise.</returns>

privatebool

        isTwoArgOp(String str)

        {

if (str == null) returnfalse;

Object o = ops[str];

if (o == null) returnfalse;

return (((Operator)o).arguments() == 2);

        }

 

 

///<summary>

/// Checks to see if the double value a can be considered to be a mathematical integer.</summary>

///<remarks>

/// This method is only used by the fac and sfac methods and not the parser itself, it should

/// really leave this class since they have nothing to do with the parser.

///</remarks>

///<param name="a">the double value to check</param>

///<returns>true if the double value is an integer, false otherwise.</returns>

privatebool

        isInteger(double a)

        {

return ((a - (int)a) == 0.0);

        }

 

 

///<summary>

/// Checks to see if the int value a can be considered to be even. </summary>

///<remarks>

/// This method is only used by the fac and sfac methods and not the parser itself, it should

/// really leave this class since they have nothing to do with the parser.

///</remarks>

///<param name="a">the int value to check</param>

///<returns>true if the int value is even, false otherwise.</returns>

privatebool

        isEven(int a)

        {

return (isInteger(a / 2));

        }

 

 

///<summary>

/// Checks to see if the character is a valid symbol for this parser.

///</summary>

///<param name="s">the character to check</param>

///<returns>true if the char is valid, false otherwise.</returns>

privatebool

        isAllowedSym(char s)

        {

return (s == ',' || s == '.' || s == ')' || s == '(' || s == '>' || s == '<' || s == '&' || s == '=' || s == '|');

        }

 

 

 

///<summary>

/// Checks the String expression to see if the syntax is valid.

/// this method doesn't return anything, instead it throws an Exception

/// if the syntax is invalid.

/// 

/// Examples of invalid syntax can be non matching paranthesis, non valid symbols appearing

/// or a variable or operator name is invalid in the expression.

///</summary>

///<param name="exp">the string expression to check, infix notation.</param>

privatevoid

        Syntax(String exp)

        {

int i = 0, oplen = 0;

String op = null;

String nop = null;

 

if (!matchParant(exp))

            {

thrownew System.Exception("Non matching paranthesis");

            }

 

int l = exp.Length;

 

while (i < l)

            {

try

                {

 

if ((op = getOp(exp, i)) != null)

                    {

                        oplen = op.Length;

                        i += oplen;

                        nop = getOp(exp, i);

if (nop != null&& isTwoArgOp(nop) && !(nop.Equals("+") || nop.Equals("-")))

                        {

thrownew System.Exception("Syntax error near -> " + exp.Substring(i - oplen));

                        }

                    }

elseif (!isAlpha(exp[i]) && !isConstant(exp[i]) && !isAllowedSym(exp[i]))

                    {

thrownew System.Exception("Syntax error near -> " + exp.Substring(i));

                    }

else

                    {

                        i++;

                    }

                }

catch (IndexOutOfRangeException)

                {

                    i++;

                }

            }

 

return;

        }

 

 

 

///<summary>

/// Inserts the multiplication operator where needed.

/// This method adds limited juxtapositioning support.

///</summary>

///<remarks> 

/// Juxtaposition is supported in these type cases:

///

/// case: variable jp one-arg-op , xcos(x)

/// case: const jp variable or one-arg-op, 2x, 2tan(x)

/// case: "const jp ( expr )" , 2(3+x)

/// case: ( expr ) jp variable or one-arg-op , (2-x)x , (2-x)sin(x)

/// case: var jp  ( expr ) , x(x+1) , x(1-sin(x))

///

/// Note that this also puts extra limitations on variable names, they cannot

/// contain digits within them or at the beginning, only at the end.

///</remarks>

///<param name="exp">the infix string expression to process</param>

///<returns>the processed infix expression</returns>

privateString

        putMult(String exp)

        {

int i = 0, p = 0;

String tmp = null;

StringBuilder str = newStringBuilder(exp);

 

int l = exp.Length;

 

while (i < l)

            {

try

                {

 

if ((tmp = getOp(exp, i)) != null&& !isTwoArgOp(tmp) && isAlpha(exp[i - 1]))

                    {

// case: variable jp one-arg-op , xcos(x)

                        str.Insert(i + p, "*");

                        p++;

                    }

elseif (isAlpha(exp[i]) && isConstant(exp[i - 1])

&& (tmp == null || !tmp.Equals("log"))) // tmp was set by previous test

                    {

 

// case: const jp variable or one-arg-op, 2x, 2tan(x)

// note that "log" is treated specially

                        str.Insert(i + p, "*");

                        p++;

                    }

elseif (exp[i] == '('&& isConstant(exp[i - 1]))

                    {

// case: "const jp ( expr )" , 2(3+x)

                        str.Insert(i + p, "*");

                        p++;

                    }

elseif (isAlpha(exp[i]) && exp[i - 1] == ')'

&& (tmp == null || !tmp.Equals("log")))  // tmp was set by previous test

                    {

// case: ( expr ) jp variable or one-arg-op , (2-x)x , (2-x)sin(x)

                        str.Insert(i + p, "*");

                        p++;

                    }

elseif (exp[i] == '('&& exp[i - 1] == ')')

                    {

// case: ( expr ) jp  ( expr ) , (2-x)(x+1) , sin(x)(2-x)

                        str.Insert(i + p, "*");

                        p++;

                    }

elseif (exp[i] == '('&& isAlpha(exp[i - 1]) && backTrack(exp.Substring(0, i)) == null)

                    {

// case: var jp  ( expr ) , x(x+1) , x(1-sin(x))

                        str.Insert(i + p, "*");

                        p++;

                    }

                }

catch { }

 

if (tmp != null)

                {

                    i += tmp.Length;

                }

else

                {

                    i++;

                }

 

                tmp = null;

            }

 

return str.ToString();

        }

 

 

 

///<summary>

/// Adds support for "scientific notation" by replacing the E operator with *10^

///</summary>

///<remarks>

/// For example the value 1E-3 would be changed to 1*10^-3 which the parser will treat

/// as a normal expression.

///</remarks>

///<param name="exp">the infix string expression to process</param>

///<returns>the processed infix expression</returns>

privateString

        parseE(String exp)

        {

 

int i, p, len;

 

StringBuilder newstr = newStringBuilder(exp);

 

            i = p = 0;

            len = exp.Length;

 

while (i < len)

            {

try

                {

if (exp[i] == 'e'&&Char.IsDigit(exp[i - 1]))

                    {

if (Char.IsDigit(exp[i + 1]) || ((exp[i + 1] == '-' || exp[i + 1] == '+') &&Char.IsDigit(exp[i + 2])))

                        {

// replace the 'e'

                            newstr[i + p] = '*';

// insert the rest

                            newstr.Insert(i + p + 1, "10^");

                            p = p + 3; // buffer growed by 3 chars

                        }

                    }

                }

catch { }

                i++;

            }

 

return newstr.ToString();

        }

 

 

///<summary>

/// Parses out spaces from a string

///</summary>

///<param name="str">The string to process</param>

///<returns>A copy of the string stripped of all spaces</returns>

privateString

        skipSpaces(String str)

        {

int i = 0;

int len = str.Length;

StringBuilder nstr = newStringBuilder(len);

 

while (i < len)

            {

if (str[i] != ' ')

                {

                    nstr.Append(str[i]);

                }

                i++;

            }

 

return nstr.ToString();

        }

 

 

 

///<summary>

/// Matches an opening left paranthesis.

///</summary>

///<param name="exp">the string to search in</param>

///<param name="index">the index of the opening left paranthesis</param>

///<returns>the index of the matching closing right paranthesis</returns>

privateint

        match(String exp, int index)

        {

int len = exp.Length;

int i = index;

int count = 0;

 

while (i < len)

            {

if (exp[i] == '(')

                {

                    count++;

                }

elseif (exp[i] == ')')

                {

                    count--;

                }

 

if (count == 0) return i;

 

                i++;

            }

 

return index;

        }

 

 

 

///<summary>

/// Parses out an operator from an infix string expression.

///</summary>

///<param name="exp">the infix string expression to look in</param>

///<param name="index">the index to start searching from</param>

///<returns>the operator if any or null.</returns>

privateString

        getOp(String exp, int index)

        {

String tmp;

int i = 0;

int len = exp.Length;

 

for (i = 0; i < maxoplength; i++)

            {

if (index >= 0 && (index + maxoplength - i) <= len)

                {

                    tmp = exp.Substring(index, maxoplength - i);

if (isOperator(tmp))

                    {

return (tmp);

                    }

                }

            }

 

returnnull;

        }

 

///<summary>

/// Parses an infix String expression and creates a parse tree of Node's.

///</summary>

///<remarks>

/// This is the heart of the parser, it takes a normal expression and creates

/// a datastructure we can easily recurse when evaluating.

///

/// The datastructure is then evaluated by the toValue method.

///</remarks>

///<param name="exp">the infix string expression to process</param>

///<returns>A tree datastructure of Node objects representing the expression</returns>

privateNode

        parse(String exp)

        {

int i, ma, len;

String farg, sarg, fop;

Node tree = null;

 

            farg = sarg = fop = "";

            ma = i = 0;

 

            len = exp.Length;

 

if (len == 0)

            {

thrownew System.Exception("Wrong number of arguments to operator");

            }

elseif (exp[0] == '('&& ((ma = match(exp, 0)) == (len - 1)))

            {

return (parse(exp.Substring(1, ma - 1)));

            }

elseif (isVariable(exp))

            {