/// <summary> /// Create and return the sub-copy of the current object</summary> /// <param name="_from">from index in current object</param> /// <param name="_to">to index in current object</param> public CBlock Projection(int _from, int _to) { CBlock block = new CBlock(); block.Init(m_NumEtalon); for (int i = _from; i <= _to; i++) { if (this[i].IsOperator) { block.BaseAdd(null, this[i].Operator); } else if (this[i].IsNumber) { block.BaseAdd(null, this[i].Number); } } return(block); }
//•••••••••••••••••••••••••••••••••••••••••••••••••••••••• // Find next operator to solve by its priority. // And, if available, return it in `_hipos` with valid status, // false otherwise private bool GetHiPriorityPos(CBlock _blocks, ref int _hipos) { bool bvalid = false; int priority = 0; int testpriority = 0; for (int i = 0; i < _blocks.Count; i++) { if (_blocks[i].IsNumber) { continue; } // here is operator testpriority = GetPriority(_blocks[i].Operator); // no priority is assigned if (!bvalid) { priority = testpriority; _hipos = i; bvalid = true; continue; } /** Assign new priority position. * operator (>) or (>=) affects in order of solving operators * with same priority: * (>) - the first operator from the left * (>=)- the last operator from the left * */ else if (testpriority > priority) { priority = testpriority; _hipos = i; } } return(bvalid); }
//•••••••••••••••••••••••••••••••••••••••••••••••••••••••• /// <summary>Find end of breace-scope specified by _iStart</summary> /// <param name="_blocks">in blocks</param> /// <param name="_iStart">at start position</param> /// <returns>position of end-brace</returns> private int FindEndBrace(CBlock _blocks, int _iStart) { STUB(_iStart < (_blocks.Count - 1) , "Bad FindEndBrace, index exceed blocks count."); STUB((_blocks[_iStart].IsOperator) && (the(AO.BRBEG) == _blocks[_iStart].Operator) , "Bad FindEndBrace, need operator."); int innerBrace = 0; for (int i = (_iStart + 1); i < _blocks.Count; i++) { if (_blocks[i].IsNumber) { continue; } if (the(AO.BRBEG) == _blocks[i].Operator) { ++innerBrace; } else if (the(AO.BREND) == _blocks[i].Operator) { if (innerBrace == 0) { return(i); } else { --innerBrace; } } } STUB(false, "End brace not found."); return(-1); // unreached code }
//•••••••••••••••••••••••••••••••••••••••••••••••••••••••• /// <summary> /// Solve unray operator, where operand taken from right of operator /// position</summary> /// <param name="_blocks">in blocks</param> /// <param name="_iHipos">at operator position</param> /// <returns>calculation result</returns> private CNumber SolveUnary(CBlock _blocks, int _iHipos) { ASSERT(((_iHipos + 1) < _blocks.Count) && (_blocks[_iHipos + 1].IsNumber) , "Missing argument for >" + _blocks[_iHipos].Operator + '<' , "SolveUnary"); string strOperator = _blocks[_iHipos].Operator; CNumber number = _blocks[_iHipos + 1].Number; CNumber res; STUB(strOperator != null && strOperator != "", "Bad _sOper in SolveUnary"); STUB(number != null, "Bad _Num in SolveUnary"); ///-- LOGIC if (the(AO.NOT) == strOperator) { res = CMath.Not(number); } ///-- ARITHMETIC else if (the(AO.MIN) == strOperator) { res = CMath.Minus(number); } else if (the(AO.PLS) == strOperator) { res = CMath.Plus(number); } else if (the(AO.ROOT) == strOperator) { // square root res = CMath.Root(number); } else if (the(AO.ABS) == strOperator) { res = CMath.Abs(number); } ///-- THRIGONOMETRY else if (the(AO.SIN) == strOperator) { res = CMath.Sin(number); } else if (the(AO.COS) == strOperator) { res = CMath.Cos(number); } else if (the(AO.EXP) == strOperator) { res = CMath.Exp(number); } else if (the(AO.TAN) == strOperator) { res = CMath.Tan(number); } ///-- FUNCTION else if (the(AO.FACT) == strOperator) { res = CMath.Factorial(number); } else if (the(AO.LG) == strOperator) { res = CMath.Lg(number); } else if (the(AO.LN) == strOperator) { res = CMath.Ln(number); } else if (the(AO.LOG) == strOperator) { res = CMath.Log(number); } else { STUB(false, "[ " + strOperator.ToUpper() + " ] not implemented unary operation!"); return(null); } ASSERT(!(double.IsInfinity(res.dValue)) , "Result is ±Infinity", "SolveUnary"); ASSERT(!(double.IsNaN(res.dValue)) , "Result is Not a number", "SolveUnary"); return(res); }
/// <summary> /// Solve binary operator, where operands taken from right and left /// of operator position</summary> /// <param name="_blocks">in blocks</param> /// <param name="_iHipos">at operator position</param> /// <returns>calculation result</returns> private CNumber SolveBinary(CBlock _blocks, int _iHipos) { ASSERT((_blocks.Count >= 3) && (_iHipos > 0) && ((_iHipos + 1) < _blocks.Count) , "Unrecovered binary operator >" + _blocks[_iHipos].Operator + '<' , "SolveBinary1"); ASSERT(_blocks[_iHipos - 1].IsNumber && _blocks[_iHipos + 1].IsNumber , "Missing argument for binary operator >" + _blocks[_iHipos].Operator + '<' , "SolveBinary2"); CNumber nLeft = _blocks[_iHipos - 1].Number; string strOperator = _blocks[_iHipos].Operator; CNumber nRight = _blocks[_iHipos + 1].Number; CNumber res; STUB((nLeft != null) && (nRight != null), "Bad _nLeft in SolveBinary."); STUB((strOperator != null) && (strOperator != ""), "Bad _sOper in SolveBinary."); ///-- ARITHMETIC if (the(AO.POW) == strOperator) { res = CMath.Pow(nLeft, nRight); } else if (the(AO.MUL) == strOperator) { res = CMath.Mul(nLeft, nRight); } else if (the(AO.DIV) == strOperator) { res = CMath.Div(nLeft, nRight); } else if (the(AO.MOD) == strOperator) { res = CMath.Mod(nLeft, nRight); } else if (the(AO.PLS) == strOperator) { res = CMath.Plus(nLeft, nRight); } else if (the(AO.MIN) == strOperator) { res = CMath.Minus(nLeft, nRight); } else if (the(AO.ROOT) == strOperator) { res = CMath.Root(nLeft, nRight); } ///-- FUNCTION else if (the(AO.LOG) == strOperator) { res = CMath.Log(nLeft, nRight); } ///-- LOGIC else if (the(AO.AND) == strOperator) { res = CMath.Log(nLeft, nRight); } else if (the(AO.OR) == strOperator) { res = CMath.Or(nLeft, nRight); } else if (the(AO.XOR) == strOperator) { res = CMath.Xor(nLeft, nRight); } ///-- BITWISE else if (the(AO.SH_LEFT) == strOperator) { res = CMath.ShiftLeft(nLeft, nRight); } else if (the(AO.SH_RIGHT) == strOperator) { res = CMath.ShiftRight(nLeft, nRight); } else if (the(AO.GCD) == strOperator) { res = CMath.GCD(nLeft, nRight); } //-- not implemented else { STUB(false, "[" + strOperator + "] not implemented binary operation!"); return(null); } ASSERT(!(double.IsInfinity(res.dValue)) , "Result is ±Infinity", "SolveBinary"); ASSERT(!(double.IsNaN(res.dValue)) , "Result is Not a number", "SolveBinary"); return(res); }
//•••••••••••••••••••••••••••••••••••••••••••••••••••••••• /// <summary> /// Solve partitionized expression. /// Assume what: /// - created valid partition (Parse_to_Blocks) /// - any registers replaced by value (..) /// - no braces conflicts (..) /// Parentheses solved in recursion call, end-condition is /// when one part is left, and its a number.</summary> /// <param name="_scPart">valid partition</param> /// <returns>answer</returns> private void Parts_Solve(CBlock _blocks) { int hipos = 0; // hi priority index int brEnd = 0; // index of found `AO.BREND` while (1 < _blocks.Count) { // find hi priority operator index if (GetHiPriorityPos(_blocks, ref hipos)) { // engage braces by self-recursion if (the(AO.BRBEG) == _blocks[hipos].Operator) { // here `hipos` is index of `AO.BRBEG` brEnd = FindEndBrace(_blocks, hipos); // copy sub-expression parts CBlock subBlocks = _blocks.Projection((hipos + 1), (brEnd - 1)); Parts_Solve(subBlocks); // enter recursion // RETURN AFTER RECURSIVE CALL WITH ONLY ONE PART ASSERT(1 == subBlocks.Count , "Invalid recursion return" , "Parts_Solve: ret from recursion"); _blocks.ReplaceWith(subBlocks[0].Number, hipos, brEnd); } /// engage unary or binary operators by priority /// Check if current operator is a double-sence operator: /// Unary have number from right, binary from both sides. else { bool unary = true; // is unray by default if (IsDoubleSenseAO(_blocks[hipos].Operator)) { // check boundaries before accesing by indexes if ((hipos > 0) && ((hipos + 1) < _blocks.Count)) { // define from context... unary = (_blocks[hipos - 1].IsOperator || _blocks[hipos + 1].IsOperator); } } else { // define from table of unary operators... unary = IsUnaryAO(_blocks[hipos].Operator); } if (unary) { m_result = this.SolveUnary(_blocks, hipos); _blocks.ReplaceWith(m_result, hipos, hipos + 1); } else // binary { m_result = SolveBinary(_blocks, hipos); _blocks.ReplaceWith(m_result, hipos - 1, hipos + 1); } } } else // priority operator not found { ASSERT(false , "Omitted operator found after >" + _blocks[0].Number + '<' , "Parts_Solve: operator not found"); } } // End solving with single number ASSERT(_blocks.Count == 1, "Nothing to solve", "Parts_Solve: 1-part,1"); ASSERT(_blocks[0].IsNumber , "Unrecovered >" + _blocks[0].Operator + "< operator" , "Parts_Solve: 1-part,2"); return; }