public INumber Eval(RuntimeData runtime) { BlockData data = runtime.NowBlock; for (int i = 0; i < this.Count; i++) { IExpression exp = this.Items[i]; if (exp is Operator) { INumber left = null, right = null; Operator op = exp as Operator; if (runtime.Setting.IsDebug) { // Console.Clear(); OutputStackData(runtime, exp); } bool willEval = true; // 後ろの方にEvalせずに実行する演算子がある場合、変数を評価しないようにする for (int j = i + 1; j < this.Count; j++) { if (this.items[j] is Operator && !(this.items[j] as Operator).Evaluator.DoEvaledParam) { willEval = false; runtime.AddBlock(new BlockData() { MoreScope = false }); if (runtime.Setting.IsDebug) { Console.WriteLine("AddBlock[MoreScope=false] しました"); } break; } } if (op.Evaluator.RequireRightParameter) { var r = data.Pop(); if (op.Evaluator.DoEvaledParam && willEval) { r = (r as IEval).Eval(runtime); } if (!op.Evaluator.DoEvaledParam && r is INumber) { } else if (r is Variable || r is Member) { } else if (r is Member) { r = (r as Member).GetVariable(runtime); } else { r = (r as IEval).Eval(runtime); } right = r as INumber; if (op.Evaluator.DoEvaledParam && willEval) { right = right.Eval(runtime); } } if (op.Evaluator.RequireLeftParameter) { var l = data.Pop(); if (op.Evaluator.DoEvaledParam && willEval) { l = (l as IEval).Eval(runtime); } if (!op.Evaluator.DoEvaledParam && l is INumber) { } else if (l is Variable) { } else if (l is Member) { l = (l as Member).GetVariable(runtime); } else { l = (l as IEval).Eval(runtime); } left = l as INumber; if (op.Evaluator.DoEvaledParam && willEval) { left = left.Eval(runtime); } } var res = (exp as Operator).Evaluator.Execute(runtime, left as INumber, right as INumber); if (res != null && runtime.Setting.DoOptimize) { res = res.Optimise(runtime); } if (!willEval) { runtime.PopBlock(); } data.Push(res); if (runtime.Setting.IsDebug) { // Console.Clear(); Console.WriteLine("Eval RPE Formula : ({0})[{1}] {2} ({3})[{4}] => {5}[{6}]", left != null ? left.ToString() : "null", left != null ? left.GetType().Name : "", (exp as Operator).Evaluator.Name, right != null ? right.ToString() : "null", right != null ? right.GetType().Name : "", res != null ? res.ToString() : "null", res != null ? res.GetType().Name : ""); OutputStackData(runtime, null); } } else { if (exp is IEval) { data.Push(exp as IEval); } else { throw new NotImplementedException(); } } } if (data.Count == 0) { return(null); } else { var result = data.Pop() as INumber; if (result != null && runtime.Setting.DoOptimize) { return(result.Optimise(runtime)); } return(result); } }
public override INumber Execute(RuntimeData runtime, params INumber[] parameters) { string varname = "x"; INumber f = parameters[0].Optimise(runtime); if (f is IConstParameter) { throw new RuntimeException("定数から方程式を評価することはできません。", parameters[0]); } if (f is Variable) { if ((f as Variable).Name == varname) { return(Number.New(0)); } else { throw new RuntimeException("この条件では方程式を解決することはできません。"); } } if (f is Member) { if ((f as Member).Text == varname) { return(Number.New(0)); } else { throw new RuntimeException("この条件では方程式を解決することはできません。"); } } if (f is MultipleFormula) { bool flag = false; MultipleFormula mf = f as MultipleFormula; for (int i = 0; i < mf.Items.Count; i++) { if (mf.Items[i] is Variable && (mf.Items[i] as Variable).Name == varname) { flag = true; } if (mf.Items[i] is Member && (mf.Items[i] as Member).Text == varname) { flag = true; } } if (flag) { return(Number.New(0)); } else { throw new RuntimeException("この条件では方程式を解決することはできません。"); } } if (!(f is AdditionFormula)) { throw new RuntimeException(string.Format("まだ '{0}' の式の解決は対応していません。", f.GetType().FullName)); } Dictionary <int, INumber> keisu = new Dictionary <int, INumber>(); // 式の係数を調べる AdditionFormula af = f as AdditionFormula; for (int i = 0; i < af.Items.Length; i++) { var item = af.Items[i]; INumber pow = null; var res = CheckMulti(runtime, varname, item, out pow); if (pow is Number) { long p = (pow as Number).Value; if (p > int.MaxValue) { throw new RuntimeException("int.MaxValueを超えるべき乗を含む式の解決はできません。"); } int ip = (int)p; if (!keisu.ContainsKey(ip)) { keisu.Add(ip, Number.New(0)); } keisu[ip] = keisu[ip].Add(runtime, res); } else { throw new RuntimeException("整数以外のべき乗の変数が指定された状態で方程式を解決することはできません。"); } } INumber result = null; // 一次方程式を解決する // 条件: x^2以上のべき乗がない // xの係数が0ではない if ((result = this.SolutionLinearEquation(runtime, varname, keisu)) != null) { return(result); } // 二次方程式を解決する // 条件: x^3以上のべき乗がない // x^2, x, 1のそれぞれの係数が実数であること // x^2の係数が0ではない if ((result = this.SolutionQuadraticEquation(runtime, varname, keisu)) != null) { return(result); } // 五次方程式を解決する // 無条件でエラーを出す。(解の公式は存在しないため計算を行うことができないため) if ((result = this.SolutionQuadraticEquation(runtime, varname, keisu)) != null) { return(result); } throw new RuntimeException("式を解決することができませんでした"); }
public override INumber Execute(RuntimeData runtime, params INumber[] parameters) { INumber left = parameters[0], right = parameters[1]; // 無効パラメータはここで弾く if (left is Fraction || left is AdditionFormula || left is MultipleFormula || left is InfinityValue || left is Variable || left is Member) { throw new RuntimeException(string.Format("exgcd関数では使用できないパラメータ '{0}'が含まれています。", left.GetType().Name), left); } if (right is Fraction || right is AdditionFormula || right is MultipleFormula || right is InfinityValue || right is Variable || right is Member) { throw new RuntimeException(string.Format("exgcd関数では使用できないパラメータ '{0}'が含まれています。", right.GetType().Name), right); } if (left is Number && right is Number) { // ユークリッドの互除法を使用して求める long l = (left as Number).Value, r = (right as Number).Value; // 引用 : http://arc360.info/algo/privatekey.html long x1, x2, y1, y2, z1, z2, q, t; x1 = 1; y1 = 0; z1 = l; x2 = 0; y2 = 1; z2 = r; while (z2 != 1) { if (z2 == 0) { break; } q = (z1 - (z1 % z2)) / z2; // Console.WriteLine("{0}a + {1}b = {2}", x1, y1, z1); x1 = x1 - (q * x2); y1 = y1 - (q * y2); z1 = z1 - (q * z2); t = x1; x1 = x2; x2 = t; t = y1; y1 = y2; y2 = t; t = z1; z1 = z2; z2 = t; } if (y2 < 0) { Console.WriteLine("({0},{1})", x2 - r, y2 + l); var res = new Expression.Array(); res.Items[0].Add(Number.New(x2 - r)); res.Items[0].Add(Number.New(y2 + l)); return(res); } else { Console.WriteLine("({0},{1})", x2, y2); var res = new Expression.Array(); res.Items[0].Add(Number.New(x2)); res.Items[0].Add(Number.New(y2)); return(res); } } else { throw new RuntimeException("exgcd関数はパラメータが整数であることが前提条件としたものなので、整数以外のパラメータが指定されている場合は計算を行うことができません。"); } }
public override INumber Execute(RuntimeData runtime, params INumber[] parameters) { INumber left = parameters[0], right = parameters[1]; // 無効パラメータはここで弾く if (left is Fraction || left is AdditionFormula || left is MultipleFormula || left is InfinityValue || left is Variable || left is Member) { throw new RuntimeException(string.Format("gcd関数では使用できないパラメータ '{0}'が含まれています。", left.GetType().Name), left); } if (right is Fraction || right is AdditionFormula || right is MultipleFormula || right is InfinityValue || right is Variable || right is Member) { throw new RuntimeException(string.Format("gcd関数では使用できないパラメータ '{0}'が含まれています。", right.GetType().Name), right); } if (left is Number && right is Number) { // ユークリッドの互除法を使用して求める Number l = (left.Clone()) as Number, r = (right.Clone()) as Number; // 並び替える if (l.Value > r.Value) { Number d = l; l = r; r = d; } // 計算する Number res = r.Clone() as Number; for (;;) { res.Value = r.Value % l.Value; if (res.Value == 0) { res = l; break; } else { r.Value = l.Value; l.Value = res.Value; } } return(res); } else { throw new NotImplementedException(); } }