吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1529|回复: 1
收起左侧

[其他转载] [批处理][算法实战009]正弦函数计算器

[复制链接]
老刘 发表于 2020-9-29 16:40
本帖最后由 老刘 于 2020-9-29 16:41 编辑

学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.lanzouj.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

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

yiwozhutou 发表于 2020-9-29 18:55
不知道干嘛用 要是军事用途比如射击角度什么或者自动瞄准 可以用吗?
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-25 23:17

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表