Files
AX-Copilot-Codex/.decompiledproj/AxCopilot/Handlers/MathEvaluator.cs

257 lines
5.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Globalization;
namespace AxCopilot.Handlers;
internal static class MathEvaluator
{
private class Evaluator
{
private readonly string _s;
private int _i;
public Evaluator(string s)
{
_s = s;
_i = 0;
}
public double Parse()
{
double result = ParseExpr();
if (_i < _s.Length)
{
throw new InvalidOperationException($"예기치 않은 문자: '{_s[_i]}'");
}
return result;
}
private double ParseExpr()
{
double num = ParseTerm();
while (_i < _s.Length && (_s[_i] == '+' || _s[_i] == '-'))
{
char c = _s[_i++];
double num2 = ParseTerm();
num = ((c == '+') ? (num + num2) : (num - num2));
}
return num;
}
private double ParseTerm()
{
double num = ParsePower();
while (_i < _s.Length && (_s[_i] == '*' || _s[_i] == '/' || _s[_i] == '%'))
{
char c = _s[_i++];
double num2 = ParsePower();
num = c switch
{
'/' => num / num2,
'*' => num * num2,
_ => num % num2,
};
}
return num;
}
private double ParsePower()
{
double num = ParseUnary();
if (_i < _s.Length && _s[_i] == '^')
{
_i++;
double y = ParseUnary();
return Math.Pow(num, y);
}
return num;
}
private double ParseUnary()
{
if (_i < _s.Length && _s[_i] == '-')
{
_i++;
return 0.0 - ParsePrimary();
}
if (_i < _s.Length && _s[_i] == '+')
{
_i++;
return ParsePrimary();
}
return ParsePrimary();
}
private double ParsePrimary()
{
if (_i >= _s.Length)
{
throw new InvalidOperationException("수식이 불완전합니다.");
}
if (_i + 1 < _s.Length && _s[_i] == '0' && _s[_i + 1] == 'x')
{
_i += 2;
int i = _i;
while (_i < _s.Length && "0123456789abcdef".Contains(_s[_i]))
{
_i++;
}
string s = _s;
int num = i;
return Convert.ToInt64(s.Substring(num, _i - num), 16);
}
if (char.IsDigit(_s[_i]) || _s[_i] == '.')
{
int i2 = _i;
while (_i < _s.Length && (char.IsDigit(_s[_i]) || _s[_i] == '.'))
{
_i++;
}
if (_i < _s.Length && _s[_i] == 'e')
{
_i++;
if (_i < _s.Length && (_s[_i] == '+' || _s[_i] == '-'))
{
_i++;
}
while (_i < _s.Length && char.IsDigit(_s[_i]))
{
_i++;
}
}
string s2 = _s;
int num = i2;
return double.Parse(s2.Substring(num, _i - num), NumberStyles.Float, CultureInfo.InvariantCulture);
}
if (_s[_i] == '(')
{
_i++;
double result = ParseExpr();
if (_i < _s.Length && _s[_i] == ')')
{
_i++;
}
return result;
}
if (char.IsLetter(_s[_i]))
{
int i3 = _i;
while (_i < _s.Length && (char.IsLetterOrDigit(_s[_i]) || _s[_i] == '_'))
{
_i++;
}
string s3 = _s;
int num = i3;
string text = s3.Substring(num, _i - num);
switch (text)
{
case "pi":
return Math.PI;
case "e":
return Math.E;
case "inf":
return double.PositiveInfinity;
default:
if (_i < _s.Length && _s[_i] == '(')
{
_i++;
double num2 = ParseExpr();
double? num3 = null;
if (_i < _s.Length && _s[_i] == ',')
{
_i++;
num3 = ParseExpr();
}
if (_i < _s.Length && _s[_i] == ')')
{
_i++;
}
if (1 == 0)
{
}
double result2;
switch (text)
{
case "sqrt":
result2 = Math.Sqrt(num2);
break;
case "abs":
result2 = Math.Abs(num2);
break;
case "ceil":
result2 = Math.Ceiling(num2);
break;
case "floor":
result2 = Math.Floor(num2);
break;
case "round":
result2 = (num3.HasValue ? Math.Round(num2, (int)num3.Value) : Math.Round(num2));
break;
case "sin":
result2 = Math.Sin(num2 * Math.PI / 180.0);
break;
case "cos":
result2 = Math.Cos(num2 * Math.PI / 180.0);
break;
case "tan":
result2 = Math.Tan(num2 * Math.PI / 180.0);
break;
case "asin":
result2 = Math.Asin(num2) * 180.0 / Math.PI;
break;
case "acos":
result2 = Math.Acos(num2) * 180.0 / Math.PI;
break;
case "atan":
result2 = Math.Atan(num2) * 180.0 / Math.PI;
break;
case "log":
result2 = (num3.HasValue ? Math.Log(num2, num3.Value) : Math.Log10(num2));
break;
case "log2":
result2 = Math.Log2(num2);
break;
case "ln":
result2 = Math.Log(num2);
break;
case "exp":
result2 = Math.Exp(num2);
break;
case "pow":
if (!num3.HasValue)
{
throw new InvalidOperationException("pow(x,y) 형식으로 사용하세요.");
}
result2 = Math.Pow(num2, num3.Value);
break;
case "min":
result2 = (num3.HasValue ? Math.Min(num2, num3.Value) : num2);
break;
case "max":
result2 = (num3.HasValue ? Math.Max(num2, num3.Value) : num2);
break;
default:
throw new InvalidOperationException("알 수 없는 함수: " + text + "()");
}
if (1 == 0)
{
}
return result2;
}
throw new InvalidOperationException("알 수 없는 식별자: " + text);
}
}
throw new InvalidOperationException($"예기치 않은 문자: '{_s[_i]}'");
}
}
public static double Evaluate(string expr)
{
Evaluator evaluator = new Evaluator(expr.Replace(" ", "").Replace("×", "*").Replace("÷", "/")
.Replace("", ",")
.ToLowerInvariant());
return evaluator.Parse();
}
}