Beispiel #1
0
        /// <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());
        }
Beispiel #2
0
        /// <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));
        }