MathExpression.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. #include "stdafx.h"
  2. #include <stdlib.h>
  3. #include <math.h>
  4. #include <float.h>
  5. #include "MathExpression.h"
  6. namespace expInterpreter {
  7. const int expr_str_err_N = 5;
  8. const char *expr_str_err[] =
  9. {
  10. "unknown error.", // error code 0
  11. "unexcepted end.", // error code 1
  12. "operator error.", // error code 2
  13. "input data error.", // error code 3
  14. "expression too long." // error code 4
  15. };
  16. const int compute_err_N = 5;
  17. const char *compute_err[] =
  18. {
  19. "unknown error.", // error code 0
  20. "compute data error.", // error code 1
  21. "input data error.", // error code 2
  22. "devided by zero.", // error code 3
  23. "pow return non." // error code 4
  24. };
  25. // 从字符串的start位置开始读一个元素放入atom,返回结束位置,若解析结束,返回-1
  26. int read_atom(Atom *atom, const char *exprStr, int start);
  27. // 从字符串尝试读取一个数字,返回结束位置,若解析结束,返回start
  28. int read_digit(double *result, const char *exprStr, int start);
  29. // 判断是否为数字符号
  30. inline bool isEmpty(char ch);
  31. // 判断是否为数字符号
  32. inline bool isDigit(char ch);
  33. // 判断是否为运算符
  34. inline bool isSymbol(char ch);
  35. // 判断是否为变量
  36. inline bool isVariable(char ch);
  37. // 获取Atom的字符表示
  38. char atom_symbol(Atom *atom);
  39. // 判断符号是否合法
  40. enum BL { F = 0, T = 1 }; // T true,F false
  41. BL legel_Atom(Atom *atom1, Atom *atom2);
  42. BL legel_Atom(char ch1, char ch2);
  43. enum CR { A = 0, B = 1, D = 2, E = 3 }; // A大于,B小于,D相等,E错误
  44. // 判断符号优先级
  45. CR compare_symbol(char ch1, char ch2);
  46. // 表达式的最大长度
  47. const int Expression::poland_MAX = 255;
  48. Expression::Expression()
  49. {
  50. this->poland = new Atom[poland_MAX];
  51. this->poland[0].type = ATOM_END;
  52. this->poland_N = 0;
  53. this->var = new double[26];
  54. for (unsigned int i = 0; i < 26; i++)
  55. {
  56. this->var[i] = 1; // 初始化所有变量为1
  57. }
  58. }
  59. Expression::~Expression()
  60. {
  61. delete[] this->poland;
  62. delete[] this->var;
  63. }
  64. int Expression::SetExprStr(const char *exprStr)
  65. {
  66. Atom Bak, Now;
  67. this->poland_N = 0;
  68. char symbol_stack[poland_MAX];
  69. int symbol_stack_N = 0;
  70. symbol_stack[symbol_stack_N++] = '#';
  71. Bak.type = ATOM_END;
  72. int index = 0;
  73. int error_code = 0;
  74. while (symbol_stack_N)
  75. {
  76. if (index < 0) // 解析式是否结束
  77. {
  78. error_code = 1;
  79. goto error_return;
  80. }
  81. index = read_atom(&Now, exprStr, index);
  82. if (!legel_Atom(&Bak, &Now)) // 判断是否合法
  83. {
  84. if (Now.type == ATOM_SYMBOL && Now.value.symbol == '-') // 尝试一元运算符的多义
  85. {
  86. Now.value.symbol = '~';
  87. if (!legel_Atom(&Bak, &Now))
  88. {
  89. error_code = 2;
  90. goto error_return;
  91. }
  92. }
  93. else
  94. {
  95. error_code = 2;
  96. goto error_return;
  97. }
  98. }
  99. switch (Now.type) // 根据类别计算
  100. {
  101. case ATOM_ERROR:
  102. error_code = 3;
  103. goto error_return;
  104. break;
  105. case ATOM_SYMBOL: // 运算符号,包括结束符号
  106. case ATOM_END:
  107. {
  108. bool poped = true;
  109. char ch = atom_symbol(&Now);
  110. while (poped)
  111. {
  112. switch (compare_symbol(symbol_stack[symbol_stack_N - 1], ch)) // 比较当前运算符和符号栈顶的优先级
  113. {
  114. case A: // 上一个符号优先级高,先完成上一个运算符的运算
  115. this->poland[this->poland_N].type = ATOM_SYMBOL;
  116. this->poland[this->poland_N].value.symbol = symbol_stack[symbol_stack_N - 1];
  117. this->poland_N++;
  118. if (this->poland_N >= poland_MAX)
  119. {
  120. error_code = 4;
  121. goto error_return;
  122. }
  123. symbol_stack_N--;
  124. poped = true;
  125. break;
  126. case B: // 这次的优先级高,则压入符号栈,等待处理
  127. symbol_stack[symbol_stack_N++] = ch;
  128. poped = false;
  129. break;
  130. case D: // 优先级相等,例如'('和')',同时弹出
  131. symbol_stack_N--;
  132. poped = false;
  133. break;
  134. case E: // 优先级出错
  135. error_code = 2;
  136. goto error_return;
  137. }
  138. }
  139. }
  140. break;
  141. case ATOM_CONSTANT: // 变量或常量,自己压入逆波兰式
  142. case ATOM_VARIABLE:
  143. this->poland[this->poland_N++] = Now;
  144. if (this->poland_N >= poland_MAX)
  145. {
  146. error_code = 4;
  147. goto error_return;
  148. }
  149. break;
  150. }
  151. Bak = Now;
  152. }
  153. this->poland[this->poland_N].type = ATOM_END;
  154. return 0;
  155. error_return:
  156. return error_code;
  157. }
  158. const char *Expression::GetExprErrorStr(int err)
  159. {
  160. return err < 1 ?
  161. expr_str_err[0] :
  162. err >= expr_str_err_N ?
  163. expr_str_err[0] :
  164. expr_str_err[err];
  165. }
  166. const char *Expression::GetResultErrorStr(int err)
  167. {
  168. return err < 1 ?
  169. compute_err[0] :
  170. err >= compute_err_N ?
  171. compute_err[0] :
  172. compute_err[err];
  173. }
  174. void Expression::SetVar(char x, double value)
  175. {
  176. if (!isVariable(x)) return;
  177. x |= 0x20; // 将变量转换为小写
  178. this->var[x - 'a'] = value;
  179. }
  180. int Expression::GetResult(double *result)
  181. {
  182. double digit[poland_MAX]; // 逆波兰式的辅助堆栈
  183. int digit_N = 0;
  184. int index = 0;
  185. int error_code = 0;
  186. for (index = 0; index < this->poland_N; index++)
  187. {
  188. switch (this->poland[index].type)
  189. {
  190. case ATOM_ERROR:
  191. error_code = 2;
  192. goto error_return;
  193. break;
  194. case ATOM_SYMBOL:
  195. switch (this->poland[index].value.symbol)
  196. {
  197. case '+':
  198. if (digit_N < 2)
  199. {
  200. error_code = 1;
  201. goto error_return;
  202. }
  203. digit[digit_N - 2] = digit[digit_N - 2] + digit[digit_N - 1];
  204. digit_N--;
  205. break;
  206. case '-':
  207. if (digit_N < 2)
  208. {
  209. error_code = 1;
  210. goto error_return;
  211. }
  212. digit[digit_N - 2] = digit[digit_N - 2] - digit[digit_N - 1];
  213. digit_N--;
  214. break;
  215. case '*':
  216. if (digit_N < 2)
  217. {
  218. error_code = 1;
  219. goto error_return;
  220. }
  221. digit[digit_N - 2] = digit[digit_N - 2] * digit[digit_N - 1];
  222. digit_N--;
  223. break;
  224. case '/':
  225. if (digit_N < 2)
  226. {
  227. error_code = 1;
  228. goto error_return;
  229. }
  230. digit[digit_N - 2] = digit[digit_N - 2] / digit[digit_N - 1];
  231. digit_N--;
  232. if (!_finite(digit[digit_N - 1]))
  233. {
  234. error_code = 3;
  235. goto error_return;
  236. }
  237. break;
  238. case '^':
  239. if (digit_N < 2)
  240. {
  241. error_code = 1;
  242. goto error_return;
  243. }
  244. digit[digit_N - 2] = pow(digit[digit_N - 2], digit[digit_N - 1]);
  245. digit_N--;
  246. if (_isnan(digit[digit_N - 1]))
  247. {
  248. error_code = 4;
  249. goto error_return;
  250. }
  251. break;
  252. case '~':
  253. if (digit_N < 1)
  254. {
  255. error_code = 1;
  256. goto error_return;
  257. }
  258. digit[digit_N - 1] = -digit[digit_N - 1];
  259. break;
  260. }
  261. break;
  262. case ATOM_CONSTANT:
  263. digit[digit_N++] = this->poland[index].value.constant;
  264. break;
  265. case ATOM_VARIABLE:
  266. digit[digit_N++] = this->var[this->poland[index].value.variable - 'a'];
  267. break;
  268. case ATOM_END:
  269. break;
  270. }
  271. }
  272. if (digit_N != 1)
  273. {
  274. error_code = 1;
  275. goto error_return;
  276. }
  277. else
  278. {
  279. *result = digit[0];
  280. return 0;
  281. }
  282. error_return:
  283. return error_code;
  284. }
  285. const Atom *Expression::GetPoland()
  286. {
  287. return this->poland;
  288. }
  289. // 兼容矩阵
  290. BL legel_matrix[10][10] =
  291. {
  292. // + - * / ^ ( ) i ~ #
  293. F, F, F, F, F, T, F, T, T, F, // +
  294. F, F, F, F, F, T, F, T, T, F, // -
  295. F, F, F, F, F, T, F, T, T, F, // *
  296. F, F, F, F, F, T, F, T, T, F, // /
  297. F, F, F, F, F, T, F, T, T, F, // ^
  298. F, F, F, F, F, T, F, T, T, F, // (
  299. T, T, T, T, T, F, T, F, F, T, // )
  300. T, T, T, T, T, F, T, F, F, T, // i
  301. F, F, F, F, F, T, F, T, F, F, // ~
  302. F, F, F, F, F, T, F, T, T, F, // #
  303. };
  304. // 兼容矩阵下标值
  305. char legel_matrix_ch[10] = { '+', '-', '*', '/', '^', '(', ')', 'i', '~', '#', };
  306. // 优先级矩阵
  307. CR cmp_matrix[9][9] =
  308. {
  309. // + - * / ^ ( ) ~ #
  310. A, A, B, B, B, B, A, B, A, // +
  311. A, A, B, B, B, B, A, B, A, // -
  312. A, A, A, A, B, B, A, B, A, // *
  313. A, A, A, A, B, B, A, B, A, // /
  314. A, A, A, A, A, B, A, B, A, // ^
  315. B, B, B, B, B, B, D, B, E, // (
  316. E, E, E, E, E, E, E, E, E, // )
  317. A, A, A, A, A, B, A, A, A, // ~
  318. B, B, B, B, B, B, E, B, D, // #
  319. };
  320. // 优先级矩阵下标值
  321. char cmp_matrix_ch[9] = { '+', '-', '*', '/', '^', '(', ')', '~', '#', };
  322. BL legel_Atom(char ch1, char ch2)
  323. {
  324. int index1 = 0;
  325. while (legel_matrix_ch[index1] != ch1 && index1 < 10) index1++;
  326. if (index1 == 10) return F;
  327. int index2 = 0;
  328. while (legel_matrix_ch[index2] != ch2 && index2 < 10) index2++;
  329. if (index2 == 10) return F;
  330. return legel_matrix[index1][index2];
  331. }
  332. char atom_symbol(Atom *atom)
  333. {
  334. switch (atom->type)
  335. {
  336. case ATOM_ERROR:
  337. return -1;
  338. case ATOM_SYMBOL:
  339. return atom->value.symbol;
  340. case ATOM_CONSTANT:
  341. case ATOM_VARIABLE:
  342. return 'i';
  343. case ATOM_END:
  344. return '#';
  345. }
  346. return -1;
  347. }
  348. BL legel_Atom(Atom *atom1, Atom *atom2)
  349. {
  350. char ch1 = atom_symbol(atom1);
  351. if (ch1 < 0) return F;
  352. char ch2 = atom_symbol(atom2);
  353. if (ch2 < 0) return F;
  354. return legel_Atom(ch1, ch2);
  355. }
  356. CR compare_symbol(char ch1, char ch2)
  357. {
  358. int index1 = 0;
  359. while (cmp_matrix_ch[index1] != ch1 && index1 < 9) index1++;
  360. if (index1 == 9) return E;
  361. int index2 = 0;
  362. while (cmp_matrix_ch[index2] != ch2 && index2 < 9) index2++;
  363. if (index2 == 9) return E;
  364. return cmp_matrix[index1][index2];
  365. }
  366. int read_atom(Atom *atom, const char *exprStr, int start)
  367. {
  368. while (isEmpty(exprStr[start])) start++;
  369. if (exprStr[start] == '\0')
  370. {
  371. atom->type = ATOM_END;
  372. return -1;
  373. }
  374. if (isVariable(exprStr[start]))
  375. {
  376. atom->type = ATOM_VARIABLE;
  377. atom->value.variable = exprStr[start] | 0x20; // 变量长度只为1,转换为小写
  378. start++;
  379. }
  380. else if (isSymbol(exprStr[start]))
  381. {
  382. atom->type = ATOM_SYMBOL;
  383. atom->value.symbol = exprStr[start];
  384. start++;
  385. }
  386. else if (isDigit(exprStr[start])) // 是数字时,调用库函数读入一个实数
  387. {
  388. double digit;
  389. start = read_digit(&digit, exprStr, start);
  390. atom->type = ATOM_CONSTANT;
  391. atom->value.constant = digit;
  392. }
  393. else
  394. {
  395. atom->type = ATOM_ERROR;
  396. start++;
  397. }
  398. return start;
  399. }
  400. int read_digit(double *result, const char *exprStr, int start) // 利用库函数读入一个实数
  401. {
  402. int len = 0;
  403. while (isDigit(exprStr[start + len])) len++;
  404. *result = atof(exprStr + start);
  405. start += len;
  406. return start;
  407. }
  408. inline bool isEmpty(char ch)
  409. {
  410. return (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n');
  411. }
  412. inline bool isDigit(char ch)
  413. {
  414. return (ch == '.' || (ch >= '0' && ch <= '9'));
  415. }
  416. const int sml_N = 7;
  417. const char sml[] = { '+', '-', '*', '/', '^', '(', ')' };
  418. inline bool isSymbol(char ch)
  419. {
  420. for (unsigned int i = 0; i < sml_N; i++)
  421. {
  422. if (ch == sml[i])
  423. return true;
  424. }
  425. return false;
  426. }
  427. inline bool isVariable(char ch)
  428. {
  429. return ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'));
  430. }
  431. }