标题: [数值计算] 批处理版逆波兰四则计算器 [打印本页]
作者: 老刘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- @Echo Off
- Setlocal Enabledelayedexpansion
- ::CODER BY 老刘 POWERD BY iBAT
- Title 【老刘编写】逆波兰四则计算器
- Path "%~dp0"
- If Not Exist "Stack_LSS.Bat" (
- Echo "Stack_LSS"缺失!
- Pause&Exit
- )
-
- Set "Stack=Call Stack_LSS"
- !Stack! :Init 运算符
- !Stack! :Init 操作数
- Echo Code By OldLiu
- Echo.
- Echo 表达式中只能出现“0123456789+-*/()”这些字符。
- Echo 计算支持分数、括号可以嵌套。
- Echo 支持负数,但负号前有运算符时需加括号。
- Echo 错误举例:6/-3 5--3*-8
- Echo 正确举例:6/(-3) 5-(-3*(-8))
- Echo 输入Quit或Exit退出。
- Echo.
- Set /p IsDebug=是否开启DEBUG模式(y/n):
- If /i "!IsDebug!" Neq "y" (
- Set "Hide=Rem"
- ) Else (
- Set "Hide="
- )
-
- :Loop
- Echo. & Set /p "中缀表达式=键入表达式>>> "
- If /i "!中缀表达式!" Equ "Quit" Exit
- If /i "!中缀表达式!" Equ "Exit" Exit
-
- Rem 中缀转后缀。
- !Stack! :Clear 运算符
- Set 后缀表达式=
- Set 可能出现负数=True
- :读取中缀表达式
- If "!中缀表达式!" == "" Goto 中缀转后缀完成
- Set "字符=!中缀表达式:~,1!"
- %Hide% Set 中缀表达式
- Set "中缀表达式=!中缀表达式:~1!"
-
- Rem 处理数字。
- Set /A "IsNum=!字符!" 2>Nul
- If "!IsNum!" EQU "!字符!" (
- Set 数字=!数字!!字符!
- Set 可能出现负数=False
- Goto 读取中缀表达式
- ) Else (
- If Defined 数字 (
- Set "后缀表达式=!后缀表达式! !数字!"
- %Hide% Set 后缀表达式
- Set 数字=
- )
- )
-
- Rem 处理左括弧。
- If "!字符!" == "(" (
- Rem 左括弧不在栈中时优先级最高,直接压栈。
- !Stack! :Push 运算符 字符
- Set 可能出现负数=True
- Goto 读取中缀表达式
- )
-
- Rem 处理右括弧。
- If "!字符!" == ")" (
- Rem 运算符出栈,直到遇到左括弧。
- :括弧中运算符输出
- !Stack! :Pop 运算符 栈顶运算符
- If "!栈顶运算符!" Neq "(" (
- Set "后缀表达式=!后缀表达式! !栈顶运算符!"
- %Hide% Set 后缀表达式
- Goto 括弧中运算符输出
- )
- Goto 读取中缀表达式
- )
-
- Rem 处理运算符。
- If "!字符!" == "-" (
- If !可能出现负数! == True (
- Rem “-”号前面没数字,补一个“0”避免后缀表达式运算错误。
- Set "后缀表达式=!后缀表达式! 0"
- %Hide% Set 后缀表达式
- )
- )
- !Stack! :IsEmpty 运算符
- If !ErrorLevel! Equ 0 (
- Rem 栈是空的,任何运算符优先级高于空栈,入栈。
- !Stack! :Push 运算符 字符
- Goto 读取中缀表达式
- ) Else (
- :运算符优先级比对
- !Stack! :Pop 运算符 栈顶运算符
- If !ErrorLevel! Equ 0 (
- Set 优先级高=False
- Rem 一切运算优先级高于栈中的左括弧。
- If "!栈顶运算符!" == "(" Set 优先级高=True
- Rem 乘除法优先级高于加减法。
- If "!栈顶运算符!" == "+" (
- If "!字符!" == "*" Set 优先级高=True
- If "!字符!" == "/" Set 优先级高=True
- )
- If "!栈顶运算符!" == "-" (
- If "!字符!" == "*" Set 优先级高=True
- If "!字符!" == "/" Set 优先级高=True
- )
- If "!优先级高!" == "True" (
- Rem 当前运算优先级高于栈顶运算优先级,入栈。
- !Stack! :Push 运算符 栈顶运算符
- !Stack! :Push 运算符 字符
- Goto 读取中缀表达式
- ) Else (
- Rem 当前运算优先级不高于栈顶运算优先级,栈顶的运算可以计算了。
- Set "后缀表达式=!后缀表达式! !栈顶运算符!"
- %Hide% Set 后缀表达式
- Rem 继续出栈,直到栈空或当前运算优先级高于栈顶运算。
- Goto 运算符优先级比对
- )
- ) Else (
- Rem 栈已经清空,任何运算符优先级高于空栈,入栈。
- !Stack! :Push 运算符 字符
- Goto 读取中缀表达式
- )
- Echo 输入的表达式有误。
- Goto Loop
- )
-
- :中缀转后缀完成
- Rem 写入最后一个数字。
- Set "后缀表达式=!后缀表达式! !数字!"
- Set 数字=
- Rem 弹出栈中所有运算符。
- !Stack! :Pop 运算符 栈顶运算符
- :运算符弹出
- Set "后缀表达式=!后缀表达式! !栈顶运算符!"
- !Stack! :Pop 运算符 栈顶运算符
- If !ErrorLevel! Equ 0 Goto 运算符弹出
- %Hide% Set 后缀表达式
-
- Rem 开始计算结果。
- !Stack! :Clear 操作数
- Call :计算结果 !后缀表达式!
- Goto 计算完成
- :计算结果
- Set 字符=%1
- Set /A "IsNum=!字符!" 2>Nul
- If "!IsNum!" EQU "!字符!" (
- Rem 数字入栈。
- !Stack! :Push 操作数 字符
- ) Else (
- Rem 遇到运算符,计算。
- Rem 从栈中弹出操作数,注意操作数2先出来。
- !Stack! :Pop 操作数 操作数2
- If !ErrorLevel! Neq 0 (
- Echo 输入的表达式有误。
- Goto Loop
- )
- !Stack! :Pop 操作数 操作数1
- If !ErrorLevel! Neq 0 (
- Echo 输入的表达式有误。
- Goto Loop
- )
- Rem 整数转为分数。
- If "!操作数1:/=!" Equ "!操作数1!" (
- Set "操作数1=!操作数1!/1"
- )
- If "!操作数2:/=!" Equ "!操作数2!" (
- Set "操作数2=!操作数2!/1"
- )
- Rem 进行运算。
- If "!字符!" Equ "*" (
- Rem 分子互乘、分母互乘。
- For /f "tokens=1,2 delims=/" %%a in ("!操作数1!") do (
- Set /A 当前结果分子=%%a
- Set /A 当前结果分母=%%b
- )
- For /f "tokens=1,2 delims=/" %%a in ("!操作数2!") do (
- Set /A 当前结果分子*=%%a
- Set /A 当前结果分母*=%%b
- )
- )
- If "!字符!" Equ "/" (
- Rem 除以一个数等于乘其倒数。
- For /f "tokens=1,2 delims=/" %%a in ("!操作数1!") do (
- Set /A 当前结果分子=%%a
- Set /A 当前结果分母=%%b
- )
- For /f "tokens=1,2 delims=/" %%a in ("!操作数2!") do (
- Set /A 当前结果分子*=%%b
- Set /A 当前结果分母*=%%a
- )
- )
- Set 加减法=False
- If "!字符!" Equ "+" Set 加减法=True
- If "!字符!" Equ "-" Set 加减法=True
- If "!加减法!" Equ "True" (
- Rem 母互乘子,并以为实,母相乘为法,实如法而一。
- For /f "tokens=1,2 delims=/" %%a in ("!操作数1!") do (
- Set /A 当前结果分子=%%a
- Set /A 当前结果分母=%%b
- )
- For /f "tokens=1,2 delims=/" %%a in ("!操作数2!") do (
- Set /A 当前结果分子=当前结果分子*%%b!字符!当前结果分母*%%a
- Set /A 当前结果分母*=%%b
- )
- )
- Rem 分数化简。
- Set /A 被除数=当前结果分子,除数=当前结果分母
- :求最大公约数
- If !除数! Equ 0 (
- Echo 除以0错误。
- Goto Loop
- )
- Set /A 余数=被除数%%除数
- If !余数! Neq 0 (
- Set /A 被除数=除数,除数=余数
- Goto 求最大公约数
- )
- Rem 结果约分。
- Set /A 当前结果分子/=除数,当前结果分母/=除数
- Set 当前结果=!当前结果分子!/!当前结果分母!
- %Hide% Echo ^(!操作数1!^)!字符!^(!操作数2!^)=!当前结果!
- !Stack! :Push 操作数 当前结果
- )
- Shift /1
- If "%1" Neq "" Goto 计算结果
- Goto :Eof
-
- :计算完成
- !Stack! :Pop 操作数 计算结果
- For /f "tokens=1,2 delims=/" %%a in ("!计算结果!") do (
- Set /A 结果分子=%%a,结果分母=%%b
- If !结果分母! Lss 0 Set /A 结果分子*=-1,结果分母*=-1
- If !结果分子! Equ 0 (
- Echo 结果:0
- ) Else If !结果分母! Equ 1 (
- Rem 结果为非0整数。
- Echo 结果:!结果分子!
- ) Else If !结果分子! Gtr !结果分母! (
- Rem 结果大于1。
- Set /A 商=结果分子/结果分母,余数=%%a%%结果分母
- Echo 结果:!结果分子!/!结果分母!=!商!…!余数!
- ) Else (
- Rem 结果小于1。
- Echo 结果:!结果分子!/!结果分母!
- )
- )
- Goto Loop
复制代码
Stack_LSS.BAT
计算测试(DEBUG模式开)- 键入表达式>>> (3*3*3/2)/((-9)/(11111*3*(1-99998/99999)))
- 中缀表达式=(3*3*3/2)/((-9)/(11111*3*(1-99998/99999)))
- 中缀表达式=3*3*3/2)/((-9)/(11111*3*(1-99998/99999)))
- 中缀表达式=*3*3/2)/((-9)/(11111*3*(1-99998/99999)))
- 后缀表达式= 3
- 中缀表达式=3*3/2)/((-9)/(11111*3*(1-99998/99999)))
- 中缀表达式=*3/2)/((-9)/(11111*3*(1-99998/99999)))
- 后缀表达式= 3 3
- 后缀表达式= 3 3 *
- 中缀表达式=3/2)/((-9)/(11111*3*(1-99998/99999)))
- 中缀表达式=/2)/((-9)/(11111*3*(1-99998/99999)))
- 后缀表达式= 3 3 * 3
- 后缀表达式= 3 3 * 3 *
- 中缀表达式=2)/((-9)/(11111*3*(1-99998/99999)))
- 中缀表达式=)/((-9)/(11111*3*(1-99998/99999)))
- 后缀表达式= 3 3 * 3 * 2
- 后缀表达式= 3 3 * 3 * 2 /
- 中缀表达式=/((-9)/(11111*3*(1-99998/99999)))
- 中缀表达式=((-9)/(11111*3*(1-99998/99999)))
- 中缀表达式=(-9)/(11111*3*(1-99998/99999)))
- 中缀表达式=-9)/(11111*3*(1-99998/99999)))
- 后缀表达式= 3 3 * 3 * 2 / 0
- 中缀表达式=9)/(11111*3*(1-99998/99999)))
- 中缀表达式=)/(11111*3*(1-99998/99999)))
- 后缀表达式= 3 3 * 3 * 2 / 0 9
- 后缀表达式= 3 3 * 3 * 2 / 0 9 -
- 中缀表达式=/(11111*3*(1-99998/99999)))
- 中缀表达式=(11111*3*(1-99998/99999)))
- 中缀表达式=11111*3*(1-99998/99999)))
- 中缀表达式=1111*3*(1-99998/99999)))
- 中缀表达式=111*3*(1-99998/99999)))
- 中缀表达式=11*3*(1-99998/99999)))
- 中缀表达式=1*3*(1-99998/99999)))
- 中缀表达式=*3*(1-99998/99999)))
- 后缀表达式= 3 3 * 3 * 2 / 0 9 - 11111
- 中缀表达式=3*(1-99998/99999)))
- 中缀表达式=*(1-99998/99999)))
- 后缀表达式= 3 3 * 3 * 2 / 0 9 - 11111 3
- 后缀表达式= 3 3 * 3 * 2 / 0 9 - 11111 3 *
- 中缀表达式=(1-99998/99999)))
- 中缀表达式=1-99998/99999)))
- 中缀表达式=-99998/99999)))
- 后缀表达式= 3 3 * 3 * 2 / 0 9 - 11111 3 * 1
- 中缀表达式=99998/99999)))
- 中缀表达式=9998/99999)))
- 中缀表达式=998/99999)))
- 中缀表达式=98/99999)))
- 中缀表达式=8/99999)))
- 中缀表达式=/99999)))
- 后缀表达式= 3 3 * 3 * 2 / 0 9 - 11111 3 * 1 99998
- 中缀表达式=99999)))
- 中缀表达式=9999)))
- 中缀表达式=999)))
- 中缀表达式=99)))
- 中缀表达式=9)))
- 中缀表达式=)))
- 后缀表达式= 3 3 * 3 * 2 / 0 9 - 11111 3 * 1 99998 99999
- 后缀表达式= 3 3 * 3 * 2 / 0 9 - 11111 3 * 1 99998 99999 /
- 后缀表达式= 3 3 * 3 * 2 / 0 9 - 11111 3 * 1 99998 99999 / -
- 中缀表达式=))
- 后缀表达式= 3 3 * 3 * 2 / 0 9 - 11111 3 * 1 99998 99999 / - *
- 中缀表达式=)
- 后缀表达式= 3 3 * 3 * 2 / 0 9 - 11111 3 * 1 99998 99999 / - * /
- 后缀表达式= 3 3 * 3 * 2 / 0 9 - 11111 3 * 1 99998 99999 / - * / /
- (3/1)*(3/1)=9/1
- (9/1)*(3/1)=27/1
- (27/1)/(2/1)=27/2
- (0/1)-(9/1)=-9/1
- (11111/1)*(3/1)=33333/1
- (99998/1)/(99999/1)=99998/99999
- (1/1)-(99998/99999)=1/99999
- (33333/1)*(1/99999)=1/3
- (-9/1)/(1/3)=-27/1
- (27/2)/(-27/1)=1/-2
- 结果:-1/2
复制代码
欢迎光临 批处理之家 (http://bbs.bathome.net/) |
Powered by Discuz! 7.2 |