/// <summary> /// 数字のみの数式を計算する /// </summary> /// <param name="f">計算式</param> /// <returns>計算結果</returns> public static async Task <double> SolveNumFormula(string f) { f = LaTeXtoFormula(f); //monos:単項式ごとに分けられたもの var monos = OperateBrackets.FindMonomials(f).ToList(); monos.Remove(""); var resmonos = new double[0]; resmonos = await monos.Select(async (mono) => { if (double.TryParse(mono, out double num))//単項式が数字だけなら先に返してしまう { return(num); } else { //括弧に隣接する加減算記号を数字として扱う mono = Regex.Replace(mono, "(\\+|\\-)\\(", "${1}1("); mono = Regex.Replace(mono, "(\\+|\\-)\\#", "${1}1*#"); var bmap = OperateBrackets.MapingBrackets(mono); //括弧が足りない場合は補完 if (bmap.Last() - bmap.First() > 0) { mono += new string(')', bmap.Last() - bmap.First()); bmap = bmap.ToList().Concat(Enumerable.Range(0, bmap.Last() - bmap.First()).Reverse()).ToArray(); } //括弧が正常な時の処理 if (bmap.First() == bmap.Last()) { //演算子で区切る(累乗以外)、括弧はそのまま残す var splitted = OperateBrackets.SplitByOperators(mono); //累乗を計算する while (splitted.Any(x => x.First() == '^')) { var n = splitted.LastOrDefault(x => x.First() == '^'); int index = splitted.LastIndexOf(n); if (index > 0) { string pastn = splitted[index - 1]; double pastfigure = 1; double nowfigure = 1; char opera = '*'; if (pastn.First() == '*' || pastn.First() == '/' || pastn.First() == '^') { opera = pastn.First(); if (!double.TryParse(pastn.Substring(1), out pastfigure)) { pastfigure = await SolveNumFormula(pastn.Substring(2, pastn.Length - 3)); } if (!double.TryParse(n.Substring(1), out nowfigure)) { nowfigure = await SolveNumFormula(n.Substring(2, n.Length - 3)); } } else { if (!double.TryParse(pastn, out pastfigure)) { pastfigure = await SolveNumFormula(pastn.Substring(1, pastn.Length - 2)); } if (!double.TryParse(n.Substring(1), out nowfigure)) { nowfigure = await SolveNumFormula(n.Substring(2, n.Length - 3)); } } splitted.RemoveAt(index); splitted.RemoveAt(index - 1); splitted.Insert(index - 1, opera + Math.Pow(pastfigure, nowfigure).ToString()); } else { throw new Exception("累乗でのエラー"); } } List <double> Numres = new List <double> { }; //各項を処理する foreach (string r in splitted) { string s = r; //最初に"*"がついていたら消す if (s.First() == '*') { s = s.Substring(1); } bool IsInverse = false; if (s.First() == '/') { IsInverse = true; //最初の"/"を消す s = s.Substring(1); } if (s.First() == '#')//関数がある時 { string funkname = Regex.Replace(s, "^#\\$(([a-z|A-Z]|π)*)\\$#.*", "$1"); string inBracket = Regex.Replace(s, "^#\\$([a-z|A-Z]|π)*\\$#\\((.*)\\)$", "$2"); int[] inbracketmap = OperateBrackets.MapingBrackets(inBracket); string CommaedinBracket = inBracket; int lug = 0; for (int i = 0; i < inBracket.Length; i++) { if (inBracket[i] == ',' && inbracketmap[i] == 0) { CommaedinBracket = CommaedinBracket.Insert(i + lug++, ","); } } List <double> inBracketValues = (await CommaedinBracket.Split(new string[1] { ",," }, StringSplitOptions.None) .Select(async(x) => await SolveNumFormula(x)) .WhenAll()).ToList(); if (IsInverse) { Numres.Add(1 / await FuncItemService.RunFunc(inBracketValues, funkname)); } else { Numres.Add(await FuncItemService.RunFunc(inBracketValues, funkname)); } } else if (s.First() == '(')//括弧に囲まれたものの時 { if (IsInverse) { Numres.Add(1 / await SolveNumFormula(s.Substring(1, s.Length - 2))); } else { Numres.Add(await SolveNumFormula(s.Substring(1, s.Length - 2))); } } else//数字のみの時 { if (IsInverse) { Numres.Add(1 / double.Parse(s)); } else { Numres.Add(double.Parse(s)); } } } return(Numres.Aggregate((now, next) => now *next)); } else { throw new Exception(AppResources.BracketsWrong); } } }).WhenAll(); return(resmonos.Sum()); }
/// <summary> /// 括弧のある式を展開 /// </summary> /// <param name="f">括弧のある式</param> /// <returns>括弧のない多項式</returns> private async static Task <Formula> Expand(string f) { //-{文字列}のときは -1{文字列}に直す f = Regex.Replace(f, "-([a-z|A-Z]|\\()", "-1$1"); //単項式に分割 var fs = OperateBrackets.FindMonomials(f).ToList(); //単項式ごとに処理 List <Formula> mf = (await fs.Select(async(m) => { if (m.First() == '*') { m.Substring(1); } if (Monomial.IsMonomial(m)) { return(new Formula(await Monomial.CreateByStr(m))); } else { //括弧に隣接する加減算記号を数字として扱う m = Regex.Replace(m, "(\\+|\\-)\\(", "${1}1("); var bmap = OperateBrackets.MapingBrackets(m); if (bmap.First() - bmap.Last() > 0) { throw new Exception(AppResources.BracketsWrong); } //括弧が足りない場合は補完 if (bmap.Last() - bmap.First() > 0) { m += new string(')', bmap.Last() - bmap.First()); bmap = bmap.ToList().Concat( Enumerable.Range(0, bmap.Last() - bmap.First()).Reverse() ).ToArray(); } //中身のない括弧を消す m = Regex.Replace(m, "\\(\\)", ""); if (m.Length == 0) { return((Formula)0); } //括弧が一致したとき if (bmap.First() == bmap.Last()) { //前に演算子がついていないときは乗算記号をつける if (!Regex.IsMatch(m.First().ToString(), "^(\\*|/|\\^|\\()$")) { m = m.Insert(0, "*"); } //累乗を処理 if (m.Contains("^")) { m = await ExpandPowAsync(m); } //扱いやすい単位まで分割 var splitteds = OperateBrackets.SplitByOperators(m); var Numerator = new List <Formula> { }; var Denominator = new List <Formula> { }; foreach (string splitted in splitteds) { if (splitted.Length == 0) { continue; } var splt = splitted; if (splt.First() == '*') { splt = splt.Substring(1); } var IsDenom = splt.First() == '/'; if (IsDenom) { splt = splt.Substring(1); } switch (splt.First()) { case '(': if (IsDenom) { Denominator.Add(await Expand(splt.Substring(1, splt.Length - 2))); } else { Numerator.Add(await Expand(splt.Substring(1, splt.Length - 2))); } break; default: if (IsDenom) { Denominator.Add(await Expand(splt)); } else { Numerator.Add(await Expand(splt)); } break; } } if (Numerator.Count() == 0) { Numerator.Add((Formula)1); } if (Denominator.Count() == 0) { Denominator.Add((Formula)1); } return(Numerator.Aggregate((now, next) => now * next) / Denominator.Aggregate((now, next) => now * next)); } else { throw new Exception(AppResources.BracketsDontMatch); } } }).WhenAll()).ToList(); return(mf.Aggregate((now, next) => now + next)); }