NCalcExtensions.cs 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. using NCalc;
  2. using System.Text.RegularExpressions;
  3. namespace Alchemy.Core.Extensions
  4. {
  5. public static class NCalcExtensions
  6. {
  7. /// <summary>
  8. /// 注册自定义函数
  9. /// </summary>
  10. /// <param name="expression"></param>
  11. /// <exception cref="ArgumentException"></exception>
  12. public static void AddExtraFunction(this Expression expression)
  13. {
  14. expression.EvaluateFunction += (name, args) =>
  15. {
  16. object paramX = args.Parameters[0].Evaluate();
  17. double doubleParamX = paramX.ToString().ToDouble();
  18. object paramY = null;
  19. double doubleParamY = 0;
  20. if (args.Parameters.Count() > 1)
  21. {
  22. paramY = args.Parameters[1].Evaluate();
  23. doubleParamY = paramY.ToString().ToDouble();
  24. }
  25. switch (name.ToLower())
  26. {
  27. // 阶乘函数
  28. case "fact":
  29. int number = paramX.ToString().ToInt();
  30. args.Result = CalculateFactorial(number);
  31. break;
  32. // 反三角函数(返回弧度)
  33. case "sin":
  34. args.Result = Math.Sin(paramX.ToString().ToDouble());
  35. break;
  36. case "cos":
  37. args.Result = Math.Cos(paramX.ToString().ToDouble());
  38. break;
  39. case "tan":
  40. args.Result = Math.Tan(paramX.ToString().ToDouble());
  41. break;
  42. // 反三角函数(返回弧度)
  43. case "arcsin":
  44. case "asin":
  45. if (doubleParamX < -1 || doubleParamX > 1)
  46. throw new ArgumentException("反正弦 x∈[-1,1]");
  47. args.Result = Math.Asin(paramX.ToString().ToDouble());
  48. break;
  49. case "arccos":
  50. case "acos":
  51. if (doubleParamX < -1 || doubleParamX > 1)
  52. throw new ArgumentException("反余弦 x∈[-1,1]");
  53. args.Result = Math.Acos(paramX.ToString().ToDouble());
  54. break;
  55. case "arctan":
  56. case "atan":
  57. args.Result = Math.Atan(paramX.ToString().ToDouble());
  58. break;
  59. // 角度/弧度转换函数
  60. case "rad": // 角度转弧度
  61. args.Result = paramX.ToString().ToDouble() * Math.PI / 180;
  62. break;
  63. //case "deg": // 弧度转角度
  64. // args.Result = Convert.ToDouble(param) * 180 / Math.PI;
  65. // break;
  66. // 平方根函数
  67. case "sqrt":
  68. if (doubleParamX < 0)
  69. throw new ArgumentException("平方根 x∈[0,+∞)");
  70. args.Result = Math.Sqrt(doubleParamX);
  71. break;
  72. // 次幂函数
  73. case "pow":
  74. args.Result = Math.Pow(doubleParamX, doubleParamY);
  75. break;
  76. }
  77. };
  78. }
  79. /// <summary>
  80. /// 注册常量
  81. /// </summary>
  82. /// <param name="expression"></param>
  83. public static void AddExtraConst(this Expression expression)
  84. {
  85. expression.Parameters["e"] = Math.E; // 自然常数 e
  86. expression.Parameters["pi"] = Math.PI; // 圆周率 π
  87. }
  88. public static object Evaluate(this string strFormula, string strAngleMode)
  89. {
  90. strFormula = Regex.Replace(
  91. strFormula,
  92. @"(\d+)\!",
  93. "fact($1)");
  94. strFormula = Regex.Replace(
  95. strFormula,
  96. @"([^\(\)^]+)\^([^\(\)^]+)",
  97. "pow($1,$2)");
  98. if (strAngleMode.Equals("deg"))
  99. {
  100. strFormula = Regex.Replace(
  101. strFormula,
  102. @"(?<!a)r?(sin|cos|tan)(?![a-z])\(([^)]+)\)",
  103. "$1(rad($2))");
  104. }
  105. strFormula = strFormula.Replace(
  106. "×",
  107. "*"
  108. ).Replace(
  109. "x",
  110. "*"
  111. ).Replace(
  112. "√",
  113. "sqrt"
  114. ).Replace(
  115. "π",
  116. "pi"
  117. ).Replace(
  118. "%",
  119. "*0.01"
  120. );
  121. Expression expression = new Expression(strFormula);
  122. expression.AddExtraFunction();
  123. expression.AddExtraConst();
  124. string strEvalResult = expression.Evaluate().ToString();
  125. double doubleResult = strEvalResult.ToDouble();
  126. double roundedResult = Math.Round(doubleResult, 6);
  127. return roundedResult;
  128. }
  129. private static int CalculateFactorial(int number)
  130. {
  131. if (number <= 1) return 1;
  132. return number * CalculateFactorial(number - 1);
  133. }
  134. }
  135. }