学SICP过程中了解到的算法,今天突发奇想用批处理实现一下。纯属娱乐,无效率可言。
其实有了正弦,其它的三角函数都好说。
正弦函数计算部分由@老刘编写。
浮点数四则运算由@MHL编写,在此表示感谢。
计算原理:
将输入的弧度诱导到[0,2*pi]之内。
sin通过公式sin(x)=3sin(x/3)-4[sin(x/3)]^3放缩为更小的sin角来计算。
而sin(x)与x在|x|<0.1时相差不大,故可用x替代。
目前设定的精度要求为|x|<0.0000001时使用x替代sin(x)。
注意事项:
放缩、累加过程通过递归实现,受批处理递归层数限制,可能溢出。
虽然改成迭代写法可以提高效率,但是真的懒得改了(逃)。
目前设定为保留25位小数,可自行修改。
使用方法:
不支持表达式,请分步计算。
计算结果会自动放入剪辑版,以供粘贴。
内建常量:%pi%
正弦计算:输入“sin 弧度”并回车。
四则计算:输入“[add/multiply/divide] 数1 数2”并回车。
仅核心代码无法运行,请从下面链接中下载。
https://oldliu001.lanzous.com/iHLCmh11pcb
核心代码:纯批处理版正弦函数计算器.bat- @set 保留小数位数=25
- @rem 保留小数位数越大越精确,但运算速度会变慢。
- @rem 由于批处理变量长度限制,不能超过100。
- @set 精度=0.0000001
- @rem 精度越小越精确,但运算速度会变慢。
-
-
- @echo off
- pushd "%~dp0"
- setlocal enabledelayedexpansion
- title 老刘编写——纯批处理正弦函数计算器
- echo 正弦函数计算部分由@老刘编写。
- echo 浮点数四则运算由@MHL编写,在此表示感谢。
- echo.
- echo 计算原理:
- echo 将输入的弧度诱导到[0,2*pi]之内。
- echo sin通过公式sin^(x^)=3sin^(x/3^)-4[sin^(x/3^)]^^3放缩为更小的sin角来计算。
- echo 而sin^(x^)与x在^|x^|^<0.1时相差不大,故可用x替代。
- echo 目前设定的精度要求为^|x^|^<!精度!时使用x替代sin^(x^)。
- echo.
- echo 注意事项:
- echo 放缩、累加过程通过递归实现,受批处理递归层数限制,可能溢出。
- echo 虽然改成迭代写法可以提高效率,但是真的懒得改了(逃)。
- echo 目前设定为保留!保留小数位数!位小数,可自行修改。
- echo.
- echo 使用方法:
- echo 不支持表达式,请分步计算。
- echo 计算结果会自动放入剪辑版,以供粘贴。
- echo 内建常量:%%pi%%
- echo 正弦计算:输入“sin 弧度”并回车。
- echo 四则计算:输入“[add/multiply/divide] 数1 数2”并回车。
- echo.
- echo.
-
- echo 关闭句柄1(标准输出)。>nul 3>nul
- rem set /a 保留小数位数3倍=保留小数位数*3
- set /a 保留小数位数+=1
- set pi=3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679
- call :_round pi !保留小数位数!
- call "multiply" !pi! 2
- set _2pi=!errorlevel!
- call :_round _2pi !保留小数位数!
-
- :loop
- set /p "command=>>> ">con
- call :!command!
- echo.>con
- goto loop
-
-
- :add
- call "plus&minus" %1 %2
- echo 计算结果:!errorlevel! >con
- set /p "=!errorlevel!"<nul | clip
- goto :eof
-
- :divide
- call "divide" %1 %2 %保留小数位数%
- echo 计算结果:!errorlevel! >con
- set /p "=!errorlevel!"<nul | clip
- goto :eof
-
- :multiply
- call "multiply" %1 %2
- echo 计算结果:!errorlevel! >con
- set /p "=!errorlevel!"<nul | clip
- goto :eof
-
- :sin
- call :_sin %1
- echo 计算结果:!errorlevel! >con
- set /p "=!errorlevel!"<nul | clip
- goto :eof
-
- :_sin
- setlocal
- set number=%1
- :__sin_loop
- call :_isBigger !number! !_2pi!
- if !errorlevel! == true (
- call "plus&minus" !number! -!_2pi!
- set number=!errorlevel!
- goto __sin_loop
- )
- call :_isBigger !number! 0
- if !errorlevel! == false (
- rem 负弧度,转为正弧度。
- call :_sin !number:~1!
- set dest=!errorlevel!
- call :_isBigger !dest! 0
- if !errorlevel! == true (
- set dest=-!dest!
- )
- ) else (
- call :_isBigger !number! !精度!
- if !errorlevel! == false (
- rem 放缩完毕,直接返回。
- set dest=!number!
- ) else (
- rem 通过sin^(x^)=3sin^(x/3^)-4[sin^(x/3^)]^^3进行放缩。
- call "divide" !number! 3 %保留小数位数%
- call :_sin !errorlevel!
- set sinNumberDivide3=!errorlevel!
- call "multiply" !sinNumberDivide3! 3
- call :_round errorlevel %保留小数位数%
- set destPart1=!errorlevel!
-
- >con set sinNumberDivide3
- call "multiply" !sinNumberDivide3! !sinNumberDivide3!
- call :_round errorlevel %保留小数位数%
- call "multiply" !errorlevel! !sinNumberDivide3!
- call :_round errorlevel %保留小数位数%
- call "multiply" !errorlevel! 4
- call :_round errorlevel %保留小数位数%
- set destPart2=!errorlevel!
- >con set destPart2
-
- rem destPart2必定是正数。
- call "plus&minus" !destPart1! -!destPart2!
- set dest=!errorlevel!
- call :_round dest %保留小数位数%
- )
- )
- for %%a in (!dest!) do endlocal&set errorlevel=%%a
- goto :eof
-
- :_isBigger number1 number2
- rem 若数1比数2大(或等),返回true,否则返回false。
- setlocal
- set number2=%2
- if "!number2:~,1!" == "-" (
- set "number2=+!number2:~1!"
- ) else (
- set "number2=-!number2!"
- )
- rem echo call "plus&minus" %1 !number2! >con
- call "plus&minus" %1 !number2!
- if "!errorlevel:~,1!" == "-" (
- set dest=false
- ) else (
- set dest=true
- )
- for %%a in (!dest!) do endlocal&set errorlevel=%%a
- rem echo 计算结果:!errorlevel! >con
- rem set /p "=!errorlevel!"<nul | clip
- goto :eof
-
- :_round 四舍五入函数(提高精度用) 变量 保留小数位数-1
- setlocal
-
- rem 备份%1,使其支持处理errorlevel。
- set number=!%1!
-
- rem 若无小数部分,直接返回。
- if "!number!" equ "!number:.=!" goto :eof
-
- rem 若位数比保留位数少,直接返回。
- set demicalPart=!number:*.=!
- set /a __round_tmp=%2-1
- for %%a in (!__round_tmp!) do (
- if "!demicalPart:~%%a,1!" equ "" goto :eof
- )
-
- rem 从最后一位向前四舍五入到指定的位数。
- set carry=0
- :__round_loop
- set /a lastNum=!demicalPart:~-1!+carry
- set carry=0
- if !lastNum! geq 5 set carry=1
- :__round_jumpin
- if "!demicalPart:~%2,1!" equ "" (
- set demicalPart=!demicalPart:~,-1!
- set /a lastNum=!demicalPart:~-1!+carry
- set carry=0
- goto __round_loop2
- )
- set demicalPart=!demicalPart:~,-1!
- goto __round_loop
-
-
- rem 若出现9+1,则继续进位。
- :__round_loop2
- if !lastNum! equ 10 (
- set demicalPart=!demicalPart:~,-1!
- set /a lastNum=!demicalPart:~-1!+1
- if "!demicalPart!" neq "" (
- goto __round_loop2
- ) else (
- set demicalPart=0
- set carry=1
- )
- ) else (
- set demicalPart=!demicalPart:~,-1!!lastNum!
- )
- call "plus&minus" !number! !carry!
- for /f "tokens=1,3 delims=. " %%a in ("!errorlevel! !demicalPart!") do endlocal&set %1=%%a.%%b
-
- rem echo 计算结果:!%1! >con
- rem set /p "=!%1!"<nul | clip
- goto :eof
复制代码
|