Board logo

标题: [数值计算] 批处理版逆波兰四则计算器 [打印本页]

作者: 老刘1号    时间: 2019-11-5 22:19     标题: 批处理版逆波兰四则计算器

本帖最后由 老刘1号 于 2020-4-10 21:42 编辑
特点:计算精确无误差。
例:(3*3*3/2)/((-9)/(11111*3*(1-99998/99999)))
VBS计算结果:-.499999999998098
该程序计算结果:-1/2

逆波兰四则计算器.bat
  1. @Echo Off
  2. Setlocal Enabledelayedexpansion
  3. ::CODER BY 老刘 POWERD BY iBAT
  4. Title 【老刘编写】逆波兰四则计算器
  5. Path "%~dp0"
  6. If Not Exist "Stack_LSS.Bat" (
  7. Echo "Stack_LSS"缺失!
  8. Pause&Exit
  9. )
  10. Set "Stack=Call Stack_LSS"
  11. !Stack! :Init 运算符
  12. !Stack! :Init 操作数
  13. Echo Code By OldLiu
  14. Echo.
  15. Echo 表达式中只能出现“0123456789+-*/()”这些字符。
  16. Echo 计算支持分数、括号可以嵌套。
  17. Echo 支持负数,但负号前有运算符时需加括号。
  18. Echo 错误举例:6/-3 5--3*-8
  19. Echo 正确举例:6/(-3) 5-(-3*(-8))
  20. Echo 输入Quit或Exit退出。
  21. Echo.
  22. Set /p IsDebug=是否开启DEBUG模式(y/n):
  23. If /i "!IsDebug!" Neq "y" (
  24. Set "Hide=Rem"
  25. ) Else (
  26. Set "Hide="
  27. )
  28. :Loop
  29. Echo. & Set /p "中缀表达式=键入表达式>>> "
  30. If /i "!中缀表达式!" Equ "Quit" Exit
  31. If /i "!中缀表达式!" Equ "Exit" Exit
  32. Rem 中缀转后缀。
  33. !Stack! :Clear 运算符
  34. Set 后缀表达式=
  35. Set 可能出现负数=True
  36. :读取中缀表达式
  37. If "!中缀表达式!" == "" Goto 中缀转后缀完成
  38. Set "字符=!中缀表达式:~,1!"
  39. %Hide% Set 中缀表达式
  40. Set "中缀表达式=!中缀表达式:~1!"
  41. Rem 处理数字。
  42. Set /A "IsNum=!字符!" 2>Nul
  43. If "!IsNum!" EQU "!字符!" (
  44. Set 数字=!数字!!字符!
  45. Set 可能出现负数=False
  46. Goto 读取中缀表达式
  47. ) Else (
  48. If Defined 数字 (
  49. Set "后缀表达式=!后缀表达式! !数字!"
  50. %Hide% Set 后缀表达式
  51. Set 数字=
  52. )
  53. )
  54. Rem 处理左括弧。
  55. If "!字符!" == "(" (
  56. Rem 左括弧不在栈中时优先级最高,直接压栈。
  57. !Stack! :Push 运算符 字符
  58. Set 可能出现负数=True
  59. Goto 读取中缀表达式
  60. )
  61. Rem 处理右括弧。
  62. If "!字符!" == ")" (
  63. Rem 运算符出栈,直到遇到左括弧。
  64. :括弧中运算符输出
  65. !Stack! :Pop 运算符 栈顶运算符
  66. If "!栈顶运算符!" Neq "(" (
  67. Set "后缀表达式=!后缀表达式! !栈顶运算符!"
  68. %Hide% Set 后缀表达式
  69. Goto 括弧中运算符输出
  70. )
  71. Goto 读取中缀表达式
  72. )
  73. Rem 处理运算符。
  74. If "!字符!" == "-" (
  75. If !可能出现负数! == True (
  76. Rem “-”号前面没数字,补一个“0”避免后缀表达式运算错误。
  77. Set "后缀表达式=!后缀表达式! 0"
  78. %Hide% Set 后缀表达式
  79. )
  80. )
  81. !Stack! :IsEmpty 运算符
  82. If !ErrorLevel! Equ 0 (
  83. Rem 栈是空的,任何运算符优先级高于空栈,入栈。
  84. !Stack! :Push 运算符 字符
  85. Goto 读取中缀表达式
  86. ) Else (
  87. :运算符优先级比对
  88. !Stack! :Pop 运算符 栈顶运算符
  89. If !ErrorLevel! Equ 0 (
  90. Set 优先级高=False
  91. Rem 一切运算优先级高于栈中的左括弧。
  92. If "!栈顶运算符!" == "(" Set 优先级高=True
  93. Rem 乘除法优先级高于加减法。
  94. If "!栈顶运算符!" == "+" (
  95. If "!字符!" == "*" Set 优先级高=True
  96. If "!字符!" == "/" Set 优先级高=True
  97. )
  98. If "!栈顶运算符!" == "-" (
  99. If "!字符!" == "*" Set 优先级高=True
  100. If "!字符!" == "/" Set 优先级高=True
  101. )
  102. If "!优先级高!" == "True" (
  103. Rem 当前运算优先级高于栈顶运算优先级,入栈。
  104. !Stack! :Push 运算符 栈顶运算符
  105. !Stack! :Push 运算符 字符
  106. Goto 读取中缀表达式
  107. ) Else (
  108. Rem 当前运算优先级不高于栈顶运算优先级,栈顶的运算可以计算了。
  109. Set "后缀表达式=!后缀表达式! !栈顶运算符!"
  110. %Hide% Set 后缀表达式
  111. Rem 继续出栈,直到栈空或当前运算优先级高于栈顶运算。
  112. Goto 运算符优先级比对
  113. )
  114. ) Else (
  115. Rem 栈已经清空,任何运算符优先级高于空栈,入栈。
  116. !Stack! :Push 运算符 字符
  117. Goto 读取中缀表达式
  118. )
  119. Echo 输入的表达式有误。
  120. Goto Loop
  121. )
  122. :中缀转后缀完成
  123. Rem 写入最后一个数字。
  124. Set "后缀表达式=!后缀表达式! !数字!"
  125. Set 数字=
  126. Rem 弹出栈中所有运算符。
  127. !Stack! :Pop 运算符 栈顶运算符
  128. :运算符弹出
  129. Set "后缀表达式=!后缀表达式! !栈顶运算符!"
  130. !Stack! :Pop 运算符 栈顶运算符
  131. If !ErrorLevel! Equ 0 Goto 运算符弹出
  132. %Hide% Set 后缀表达式
  133. Rem 开始计算结果。
  134. !Stack! :Clear 操作数
  135. Call :计算结果 !后缀表达式!
  136. Goto 计算完成
  137. :计算结果
  138. Set 字符=%1
  139. Set /A "IsNum=!字符!" 2>Nul
  140. If "!IsNum!" EQU "!字符!" (
  141. Rem 数字入栈。
  142. !Stack! :Push 操作数 字符
  143. ) Else (
  144. Rem 遇到运算符,计算。
  145. Rem 从栈中弹出操作数,注意操作数2先出来。
  146. !Stack! :Pop 操作数 操作数2
  147. If !ErrorLevel! Neq 0 (
  148. Echo 输入的表达式有误。
  149. Goto Loop
  150. )
  151. !Stack! :Pop 操作数 操作数1
  152. If !ErrorLevel! Neq 0 (
  153. Echo 输入的表达式有误。
  154. Goto Loop
  155. )
  156. Rem 整数转为分数。
  157. If "!操作数1:/=!" Equ "!操作数1!" (
  158. Set "操作数1=!操作数1!/1"
  159. )
  160. If "!操作数2:/=!" Equ "!操作数2!" (
  161. Set "操作数2=!操作数2!/1"
  162. )
  163. Rem 进行运算。
  164. If "!字符!" Equ "*" (
  165. Rem 分子互乘、分母互乘。
  166. For /f "tokens=1,2 delims=/" %%a in ("!操作数1!") do (
  167. Set /A 当前结果分子=%%a
  168. Set /A 当前结果分母=%%b
  169. )
  170. For /f "tokens=1,2 delims=/" %%a in ("!操作数2!") do (
  171. Set /A 当前结果分子*=%%a
  172. Set /A 当前结果分母*=%%b
  173. )
  174. )
  175. If "!字符!" Equ "/" (
  176. Rem 除以一个数等于乘其倒数。
  177. For /f "tokens=1,2 delims=/" %%a in ("!操作数1!") do (
  178. Set /A 当前结果分子=%%a
  179. Set /A 当前结果分母=%%b
  180. )
  181. For /f "tokens=1,2 delims=/" %%a in ("!操作数2!") do (
  182. Set /A 当前结果分子*=%%b
  183. Set /A 当前结果分母*=%%a
  184. )
  185. )
  186. Set 加减法=False
  187. If "!字符!" Equ "+" Set 加减法=True
  188. If "!字符!" Equ "-" Set 加减法=True
  189. If "!加减法!" Equ "True" (
  190. Rem 母互乘子,并以为实,母相乘为法,实如法而一。
  191. For /f "tokens=1,2 delims=/" %%a in ("!操作数1!") do (
  192. Set /A 当前结果分子=%%a
  193. Set /A 当前结果分母=%%b
  194. )
  195. For /f "tokens=1,2 delims=/" %%a in ("!操作数2!") do (
  196. Set /A 当前结果分子=当前结果分子*%%b!字符!当前结果分母*%%a
  197. Set /A 当前结果分母*=%%b
  198. )
  199. )
  200. Rem 分数化简。
  201. Set /A 被除数=当前结果分子,除数=当前结果分母
  202. :求最大公约数
  203. If !除数! Equ 0 (
  204. Echo 除以0错误。
  205. Goto Loop
  206. )
  207. Set /A 余数=被除数%%除数
  208. If !余数! Neq 0 (
  209. Set /A 被除数=除数,除数=余数
  210. Goto 求最大公约数
  211. )
  212. Rem 结果约分。
  213. Set /A 当前结果分子/=除数,当前结果分母/=除数
  214. Set 当前结果=!当前结果分子!/!当前结果分母!
  215. %Hide% Echo ^(!操作数1!^)!字符!^(!操作数2!^)=!当前结果!
  216. !Stack! :Push 操作数 当前结果
  217. )
  218. Shift /1
  219. If "%1" Neq "" Goto 计算结果
  220. Goto :Eof
  221. :计算完成
  222. !Stack! :Pop 操作数 计算结果
  223. For /f "tokens=1,2 delims=/" %%a in ("!计算结果!") do (
  224. Set /A 结果分子=%%a,结果分母=%%b
  225. If !结果分母! Lss 0 Set /A 结果分子*=-1,结果分母*=-1
  226. If !结果分子! Equ 0 (
  227. Echo 结果:0
  228. ) Else If !结果分母! Equ 1 (
  229. Rem 结果为非0整数。
  230. Echo 结果:!结果分子!
  231. ) Else If !结果分子! Gtr !结果分母! (
  232. Rem 结果大于1。
  233. Set /A 商=结果分子/结果分母,余数=%%a%%结果分母
  234. Echo 结果:!结果分子!/!结果分母!=!商!…!余数!
  235. ) Else (
  236. Rem 结果小于1。
  237. Echo 结果:!结果分子!/!结果分母!
  238. )
  239. )
  240. Goto Loop
复制代码
Stack_LSS.BAT
计算测试(DEBUG模式开)
  1. 键入表达式>>> (3*3*3/2)/((-9)/(11111*3*(1-99998/99999)))
  2. 中缀表达式=(3*3*3/2)/((-9)/(11111*3*(1-99998/99999)))
  3. 中缀表达式=3*3*3/2)/((-9)/(11111*3*(1-99998/99999)))
  4. 中缀表达式=*3*3/2)/((-9)/(11111*3*(1-99998/99999)))
  5. 后缀表达式= 3
  6. 中缀表达式=3*3/2)/((-9)/(11111*3*(1-99998/99999)))
  7. 中缀表达式=*3/2)/((-9)/(11111*3*(1-99998/99999)))
  8. 后缀表达式= 3 3
  9. 后缀表达式= 3 3 *
  10. 中缀表达式=3/2)/((-9)/(11111*3*(1-99998/99999)))
  11. 中缀表达式=/2)/((-9)/(11111*3*(1-99998/99999)))
  12. 后缀表达式= 3 3 * 3
  13. 后缀表达式= 3 3 * 3 *
  14. 中缀表达式=2)/((-9)/(11111*3*(1-99998/99999)))
  15. 中缀表达式=)/((-9)/(11111*3*(1-99998/99999)))
  16. 后缀表达式= 3 3 * 3 * 2
  17. 后缀表达式= 3 3 * 3 * 2 /
  18. 中缀表达式=/((-9)/(11111*3*(1-99998/99999)))
  19. 中缀表达式=((-9)/(11111*3*(1-99998/99999)))
  20. 中缀表达式=(-9)/(11111*3*(1-99998/99999)))
  21. 中缀表达式=-9)/(11111*3*(1-99998/99999)))
  22. 后缀表达式= 3 3 * 3 * 2 / 0
  23. 中缀表达式=9)/(11111*3*(1-99998/99999)))
  24. 中缀表达式=)/(11111*3*(1-99998/99999)))
  25. 后缀表达式= 3 3 * 3 * 2 / 0 9
  26. 后缀表达式= 3 3 * 3 * 2 / 0 9 -
  27. 中缀表达式=/(11111*3*(1-99998/99999)))
  28. 中缀表达式=(11111*3*(1-99998/99999)))
  29. 中缀表达式=11111*3*(1-99998/99999)))
  30. 中缀表达式=1111*3*(1-99998/99999)))
  31. 中缀表达式=111*3*(1-99998/99999)))
  32. 中缀表达式=11*3*(1-99998/99999)))
  33. 中缀表达式=1*3*(1-99998/99999)))
  34. 中缀表达式=*3*(1-99998/99999)))
  35. 后缀表达式= 3 3 * 3 * 2 / 0 9 - 11111
  36. 中缀表达式=3*(1-99998/99999)))
  37. 中缀表达式=*(1-99998/99999)))
  38. 后缀表达式= 3 3 * 3 * 2 / 0 9 - 11111 3
  39. 后缀表达式= 3 3 * 3 * 2 / 0 9 - 11111 3 *
  40. 中缀表达式=(1-99998/99999)))
  41. 中缀表达式=1-99998/99999)))
  42. 中缀表达式=-99998/99999)))
  43. 后缀表达式= 3 3 * 3 * 2 / 0 9 - 11111 3 * 1
  44. 中缀表达式=99998/99999)))
  45. 中缀表达式=9998/99999)))
  46. 中缀表达式=998/99999)))
  47. 中缀表达式=98/99999)))
  48. 中缀表达式=8/99999)))
  49. 中缀表达式=/99999)))
  50. 后缀表达式= 3 3 * 3 * 2 / 0 9 - 11111 3 * 1 99998
  51. 中缀表达式=99999)))
  52. 中缀表达式=9999)))
  53. 中缀表达式=999)))
  54. 中缀表达式=99)))
  55. 中缀表达式=9)))
  56. 中缀表达式=)))
  57. 后缀表达式= 3 3 * 3 * 2 / 0 9 - 11111 3 * 1 99998 99999
  58. 后缀表达式= 3 3 * 3 * 2 / 0 9 - 11111 3 * 1 99998 99999 /
  59. 后缀表达式= 3 3 * 3 * 2 / 0 9 - 11111 3 * 1 99998 99999 / -
  60. 中缀表达式=))
  61. 后缀表达式= 3 3 * 3 * 2 / 0 9 - 11111 3 * 1 99998 99999 / - *
  62. 中缀表达式=)
  63. 后缀表达式= 3 3 * 3 * 2 / 0 9 - 11111 3 * 1 99998 99999 / - * /
  64. 后缀表达式= 3 3 * 3 * 2 / 0 9 - 11111 3 * 1 99998 99999 / - * /  /
  65. (3/1)*(3/1)=9/1
  66. (9/1)*(3/1)=27/1
  67. (27/1)/(2/1)=27/2
  68. (0/1)-(9/1)=-9/1
  69. (11111/1)*(3/1)=33333/1
  70. (99998/1)/(99999/1)=99998/99999
  71. (1/1)-(99998/99999)=1/99999
  72. (33333/1)*(1/99999)=1/3
  73. (-9/1)/(1/3)=-27/1
  74. (27/2)/(-27/1)=1/-2
  75. 结果:-1/2
复制代码





欢迎光临 批处理之家 (http://bbs.bathome.net/) Powered by Discuz! 7.2