//•••••••••••••••••••••••••••••••••••••••••••••••••••••••• public static CNumber Cos(CNumber _num) { m_res = new CNumber("0", _num); m_res.Value = Math.Cos(_num.ToRadians); return(m_res); }
//•••••••••••••••••••••••••••••••••••••••••••••••••••••••• /// <summary> /// Solve user expression, may throw Calc.SyntaxException, /// Calc.CommandException, Calc.EngineException.</summary> /// <param name="_sExpr">user expression</param> /// <param name="_Answer">user answer holder, where /// solved expression result is placed</param> public void Solve(string _sExpr, ref CNumber _Answer) {// void expression equals to void result if (_sExpr == null || _sExpr == "") { return; } _sExpr = _sExpr.Replace(" ", "").ToLower(); // simplify CatchCommand(_sExpr); // if command - execute // reinit & assimilate template number properties m_block.Init(_Answer); // `m_result` will like the caller answer holder and will take // a part in temporary calculations through `Parts_Solve` and // Parse_to_Blocks; m_result = new CNumber("0", _Answer); try { Parse_to_Blocks(_sExpr); } catch (ServiceException xcp) { ASSERT(false, xcp.Message, "Solve.conversion"); } Parts_Solve(m_block); // set user answer holder and common answer registry to // a newly solved value _Answer = m_block[0].Number; m_reg.ANSWER.GetProperties(_Answer); m_reg.ANSWER = _Answer; return; }
/// <summary> /// Absolute of value `_N` /// </summary> /// <param name="_N">value to take from absolut</param> /// <returns></returns> public static CNumber Abs(CNumber _N) { m_res = new CNumber("0", _N); m_res.Value = Math.Abs(_N.dValue); return(m_res); }
//•••••••••••••••••••••••••••••••••••••••••••••••••••••••• public static CNumber Mul(CNumber _N1, CNumber _N2) { m_res = new CNumber("0", _N1); m_res.Value = _N1.dValue * _N2.dValue; return(m_res); }
//•••••••••••••••••••••••••••••••••••••••••••••••••••••••• /// <summary> /// Mod devision /// </summary> /// <param name="_N"></param> /// <param name="_NBase">base of mod devision</param> /// <returns></returns> public static CNumber Mod(CNumber _N, CNumber _NBase) { m_res = new CNumber("0", _N); m_res.Value = _N.dValue % _NBase.dValue; return(m_res); }
//•••••••••••••••••••••••••••••••••••••••••••••••••••••••• public static CNumber Pow(CNumber _num, CNumber _NDegree) { m_res = new CNumber("0", _num); m_res.Value = Math.Pow(_num.dValue, _NDegree.dValue); return(m_res); }
//•••••••••••••••••••••••••••••••••••••••••••••••••••••••• // unary minus public static CNumber Minus(CNumber _num) { m_res = new CNumber("0", _num); m_res.Value = -(_num.dValue); return(m_res); }
//•••••••••••••••••••••••••••••••••••••••••••••••••••••••• /// <summary>Unary Logarithm fo base 10</summary> /// <param name="_num">argument</param> /// <returns>Returns the base 10 logarithm of a specified number</returns> public static CNumber Log(CNumber _num) { m_res = new CNumber("0", _num); m_res.Value = Math.Log10(_num.dValue); return(m_res); }
//•••••••••••••••••••••••••••••••••••••••••••••••••••••••• /// <summary> /// Root of variable degree /// </summary> /// <param name="_NDegree">root degree</param> /// <param name="_N">value, root of which to be taken</param> /// <returns>result of variable degree</returns> public static CNumber Root(CNumber _NDegree, CNumber _N) { CCalculator.ASSERT((_NDegree.dValue != 0.0d) , "(y)_#(x): `y` - Root degree can't be NULL.", "CMath.Root binary"); CCalculator.ASSERT((_N.dValue >= 0.0d) || (_NDegree.dValue % 2 != 0) , "(y)_#(x): `x` - Must be positive and/or `y` is even." , "CMath.Root binary"); m_res = new CNumber("0", _N); m_res.Value = _N.Value; double X = Math.Abs(_N.dValue); try { m_res.Value = Math.Pow(2, Math.Log(X, 2) / _NDegree.dValue); // changing sign of result if root argument was negative and // root degree was uneven if (_N.dValue < 0) { m_res.Value = -m_res.dValue; } } catch (OverflowException) { CCalculator.ASSERT(false, "", ""); } return(m_res); }
//•••••••••••••••••••••••••••••••••••••••••••••••••••••••• public static CNumber Sin(CNumber _num) { m_res = new CNumber("0", _num); // TODO: Check whenever `_num` passed here from some register // and TCS from GUI is applied for him. m_res.Value = Math.Sin(_num.ToRadians); return(m_res); }
//•••••••••••••••••••••••••••••••••••••••••••••••••••••••• /// <summary> /// Square root (degree of 2)</summary> /// <param name="_N">value, root of which to be evaluated</param> /// <returns>result of root of degree 2</returns> public static CNumber Root(CNumber _N) { CCalculator.ASSERT(_N.dValue > 0.0d , "#(x): x - Must be positive.", "CMath.Root unary"); m_res = new CNumber("0", _N); m_res.Value = Math.Sqrt(_N.dValue); return(m_res); }
//•••••••••••••••••••••••••••••••••••••••••••••••••••••••• /// <summary> /// Regular devision /// </summary> /// <param name="_NDividend"></param> /// <param name="_NDivisor"></param> /// <returns></returns> public static CNumber Div(CNumber _NDividend, CNumber _NDivisor) { m_res = new CNumber("0", _NDividend); CCalculator.ASSERT(_NDivisor.dValue != 0.0d , "Divide by zero.", "CMath.Div"); m_res.Value = _NDividend.dValue / _NDivisor.dValue; return(m_res); }
//•••••••••••••••••••••••••••••••••••••••••••••••••••••••• public static CNumber Xor(CNumber _N1, CNumber _N2) { CCalculator.ASSERT(_N1.IsInteger && _N2.IsInteger , "\"XOR\" operation need integer.", "CMath.Xor"); m_res = new CNumber("0", _N1); m_res.Value = (long)_N1.Value ^ (long)_N2.Value; return(m_res); }
//•••••••••••••••••••••••••••••••••••••••••••••••••••••••• public static CNumber Not(CNumber _num) { CCalculator.ASSERT(_num.IsInteger , "\"NOT\" operation need integer.", "CMath.Not"); m_res = new CNumber("0", _num); m_res.Value = ~((long)_num.Value); return(m_res); }
public CNumber(string _sNum, CNumber _Etalon) { InitDefaults(); m_cs = _Etalon.m_cs; m_tcs = _Etalon.m_tcs; m_prec = _Etalon.m_prec; this.FromString(_sNum); }
//•••••••••••••••••••••••••••••••••••••••••••••••••••••••• /// <summary>Binary Logarithm of variable base</summary> /// <param name="_base">base</param> /// <param name="_num">argument</param> /// <returns>Returns the _sBase logarithm of a specified number</returns> public static CNumber Log(CNumber _base, CNumber _num) { CCalculator.ASSERT(_base.dValue >= 0 , "(y)Log(x): y - POSITIVE expected." , "CMath.Log"); m_res = new CNumber("0", _num); m_res.Value = Math.Log(_num.dValue, _base.dValue); return(m_res); }
/// <summary>Binary. Find the grat common devisor of two /// integer numbers</summary> static public CNumber GCD(CNumber _n1, CNumber _n2) { CCalculator.ASSERT(_n1.IsInteger && _n2.IsInteger , "(x)Gcd(y): x, y - Integers expected.", "CMath.GCD"); m_res = new CNumber("0", _n1); m_res.Value = _gcd(_n1.lValue, _n2.lValue); return(m_res); }
/// <summary> /// Replace sub-section of the current block with _Res</summary> /// <param name="_Res">replace by this CNumber</param> /// <param name="_from">from index (included)</param> /// <param name="_to">to index (included)</param> public void ReplaceWith(CNumber _Res, int _from, int _to) { // remove next for (int i = _from; i < _to; i++) { this.BaseRemoveAt(_from); } /** insertion in this collection is impossible, * use that fact what last item to remove is always the number * so replace that number with new result * (cant do it at the `_from` becose there may be an operator, * but to assign a number need to reset the key to null and this * impossible without rebuilding all collection) * */ this.BaseSet(_from, _Res); }
//•••••••••••••••••••••••••••••••••••••••••••••••••••••••• public static CNumber ShiftRight(CNumber _N, CNumber _BitNum) { CCalculator.ASSERT(_N.IsInteger && _BitNum.IsInteger , "\">>\" operation need integer.", "CMath.ShiftRight"); m_res = new CNumber("0", _N); try { int bitNum = Convert.ToInt32((long)_BitNum.Value); m_res.Value = (long)_N.Value >> bitNum; } catch (OverflowException) { CCalculator.ASSERT(false, "\"x >> Y\" - Y overflow.", "CMath.ShiftRight"); } return(m_res); }
//•••••••••••••••••••••••••••••••••••••••••••••••••••••••• public static CNumber Factorial(CNumber _num) { CCalculator.ASSERT(_num.IsInteger , "\"!x\" operation need integer.", "CMath.Factorial"); m_res = new CNumber("0", _num); if ((long)_num.Value == 0) { m_res.Value = 1L; return(m_res); } try { if (_num.dValue <= 20) { long num = (long)_num.Value; long fact = num; while (num > 1) { fact *= --num; } m_res.Value = fact; } else { double num = _num.dValue; double fact = num; while (num > 1) { fact *= --num; } m_res.Value = fact; } } catch (OverflowException) { CCalculator.ASSERT(false , "Result is out of range.", "CMath.Factorial"); } return(m_res); }
public void AddNumber(CNumber _Number) { this.BaseAdd(null, _Number); }
/// <summary> /// Clears all the elements in the collection.</summary> public void Init(CNumber _Template) { this.BaseClear(); m_NumEtalon.GetProperties(_Template); }
public CBlockClaster() { m_sOperator = null; m_Number = null; }
/// <summary> /// Copy count-systems characteristics. /// </summary> /// <param name="_num">get from reference</param> public void GetProperties(CNumber _num) { m_cs = _num.m_cs; m_tcs = _num.m_tcs; m_prec = _num.m_prec; }
//•••••••••••••••••••••••••••••••••••••••••••••••••••••••• // unarty plus public static CNumber Plus(CNumber _num) { return(_num); }
//•••••••••••••••••••••••••••••••••••••••••••••••••••••••• /// <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; }