本帖最后由 techon 于 2011-5-27 19:15 编辑
废话一大堆,删了
方法原理见算数开平方法则
通用性处理,可支持任意数字输入,结果保留8-9位有效数字
其他算法:
二楼 版主的 牛顿迭代法快速求平方根或近似值,只能计算1-214748,保留两位小数
七楼 caruko的 使用二进制位移法开平方,支持1-2147483646,最多保留4位小数
代码如下:
保留了部分测试代码和注释,欢迎批评指正
用法 call :_Sqrt 被开方数字- @echo off
- SETLOCAL ENABLEDELAYEDEXPANSION
- rem 这是测试部分
- set x=1.4233599273013201
- set max=14233599273013201
- rem set Max = 2147483647 小于2的31次方-1(2^31=2147483648)32位有符号数可表示的最大值 set/a 可处理的最大数(32位系统是这个,64位系统未测试)
- rem 11930464 * 20 * 9 + 9^2 = 2147483601 11930464^2 = 142335971255296
- rem 119304649 119304649^2 = 14233599273013201 (可正常开完的最大被开方数)
-
- rem %1=被开方数 这是结果写在这方便比对
- call :_Sqrt 2250000000000 1500000
- echo --------jg===%jg%---------&pause
- call :_Sqrt 1000000 1000
- echo --------jg===%jg%---------&pause
- call :_Sqrt 0 0
- echo --------jg===%jg%---------&pause
- call :_Sqrt 00000.00000001 0.0001
- echo --------jg===%jg%---------&pause
- call :_Sqrt 26 5.0990195135927848300282241090228
- echo --------jg===%jg%---------&pause
- call :_Sqrt %x% 1.19304649
- echo --------jg===%jg%---------&pause
- call :_Sqrt %max% 119304649
- echo --------jg===%jg%---------&pause
- call :_Sqrt 11112233445643274231572 105414578904.64332842651254712323
- echo --------jg===%jg%---------&pause
- call :_Sqrt 2.250000000000000 1.5
- echo --------jg===%jg%---------&pause
- call :_Sqrt 0.000001 0.001
- call :_Sqrt 01111.5643274231572 33.340130884913412409133565742286
- call :_Sqrt 1048576 1024
- call :_Sqrt 0.0132010 0.114895604
- call :_Sqrt 0.00000064 0.0008
- echo --------jg===%jg%---------&pause
- call :_Sqrt 55 7.4161984870956629487113974408007
- call :_Sqrt 4.00000000 2
- echo --------jg===%jg%---------&pause
- rem 做成子程序了,方便调用
- pause&pause
- goto :EOF
-
- rem 开方程序开始
- :_Sqrt
- SETLOCAL ENABLEDELAYEDEXPANSION
- rem 检查输入是否有效
- set a=0&set sr=0&set tmpin=%1
- if "!tmpin!"=="" set sr=-1&goto :chkend
- :chkloop
- if "!tmpin:~%a%,1!"=="." (set/a sr+=1&if !sr! gtr 1 set sr=-1&goto :chkend) ^
- else (if !tmpin:~%a%^,1! lss 0 set sr=-1&goto :chkend)&if !tmpin:~%a%^,1! gtr 9 set sr=-1&goto :chkend
- set/a a+=1
- if not "!tmpin:~%a%,1!"=="" goto :chkloop
- :chkend
-
- rem 初始化变量
- set jg=0&set xs=0&set xsl=0&set fxs=0&set of=0&set pl=0&set d=0&set x1=&set x2=&set tlc=
-
- if %sr% equ -1 ENDLOCAL&set jg=被开方数字非法&echo Call :_Sqrt 输入的参数无效&goto :EOF
- if %sr% equ 0 ( rem 无小数点
- call :_dez l %tmpin% xa
- if "!xa!"=="" set xa=0
- ) else ( rem 有小数点输入
- for /f "tokens=1,2 delims=." %%C in ("0%tmpin%") do (
- call :_dez l %%C
- set x1=!dez!
- call :_dez r %%D
- set x2=!dez!
- rem 处理输入数 可将 0.xxx 简略为 .xxx 输入,取输入的整数部分为 x1,小数部分为x2
- if "!x2!"=="" ( rem 没有小数
- if "!x1!"=="" (set xa=0) else set xa=!x1!
- ) else ( rem 有小数
- call :_lenc !x2!
- set/a tlc=lenc%%2
- if !tlc! equ 1 set x2=!x2!0
- rem 小数位数如果为奇数,将其后补0,凑为偶数位
- set/a xsl=^(lenc+1^)/2
- rem 输入小数的位数除以2,开完平方后需要补回的小数位数
- if "!x1!"=="" call :_dez l !x2! x2
- set xa=!x1!!x2!
- )
- )
- )
-
- if "%x2%"=="" ( rem 如果没有小数部分,去掉整数低位2n个0,设置小数位数为负
- :lx1
- if "!xa:~-2!"=="00" set xa=!xa:~0,-2!&set/a xsl-=1&goto :lx1
- )
-
- set j19=0
- for /l %%C in (0,1,9) do ( rem 如果是1-9的平方数直接给出结果
- set/a jc=%%C*%%C
- if "!xa!"=="!jc!" (
- if %xsl% equ 0 echo 结果=%%C&ENDLOCAL&set jg=%%C&goto :EOF
- set _jg=%%C&set jg=%%C
- :xsub
- if !xsl! lss 0 set jg=!jg!0&set/a xsl+=1&goto :xsub
- :xsad
- if !xsl! gtr 0 set jg=0.!_jg!&set _jg=0!_jg!&set/a xsl-=1&goto :xsad
- set j19=1
- )
- )
- if "%j19%"=="1" echo 结果=%jg%&ENDLOCAL&set jg=%jg%&goto :EOF
-
- call :_lenc %xa%
- set/a la="lenc%%2"
- rem 将xa补位为偶数位
- if %la% equ 1 set xa=0%xa%
-
- rem 开方循环开始
- :_sqr
- set p=!xa:~%pl%,2!
- if %d% equ 0 (
- if "%p%"=="" (
- echo 开方正好开尽^^_^^&goto :_endsqr
- ) else (
- if %jg% gtr 11930464 set of=1&echo 产生溢出!!!&goto :_endsqr
- if "!p:~0,1!"=="0" (set ps=%p:~1,1%) else (set ps=%p%)
- )
- ) else (
- if %jg% gtr 11930464 set of=1&echo 产生溢出!!!&goto :_endsqr
- if "%p%"=="" set p=00&set/a xs+=1
- set ps=%d%!p!
- )
- for /l %%C in (9,-1,0) do (
- set/a ts=20*%%C*jg+%%C*%%C
- if !ts! leq %ps% (
- if not "%jg%"=="0" (set jg=%jg%%%C) else set jg=%%C
- set/a d=ps-ts&goto :_sh
- )
- )
- :_sh
- set/a pl+=2&goto :_sqr
- rem 开方循环结束
- :_endsqr
-
- if not "!xa:~%pl%!"=="" (
- call :_lenc !xa:~%pl%!
- if "!tlc!"=="1" (set/a fxs=lenc-1) else (set fxs=!lenc!)
- echo 忽略位数:fxs===!fxs! rem 溢出后将被开方数忽略的位数
- )
- set/a xsl=xsl+xs-(fxs+1)/2
- rem 修正小数位数
- echo 小数位数:%xsl% rem 开方结果小数的位数
- if %fxs% gtr 0 if %xsl% lss 0 echo 非有效位数 %xsl:~1%
-
- if %xsl% gtr 0 (
- call :_lenc %jg%
- if !lenc! gtr %xsl% (
- set jg=!jg:~0,-%xsl%!.!jg:~-%xsl%!
- ) else (
- set/a jgl=xsl-lenc
- :ld0
- if !jgl! gtr 0 set jg=0%jg%&set/a jgl-=1&goto :ld0
- set jg=0.%jg%
- )
- )
- :ad0
- if %xsl% lss 0 set jg=%jg%0&set/a xsl+=1&goto :ad0
- if %of% equ 1 (set fh=≈) else (set fh==)
- echo 结果%fh%%jg%&ENDLOCAL&set jg=%jg%&goto :EOF
- rem End_Sqrt
-
- rem 计算字串长度子程序
- :_lenc
- SETLOCAL ENABLEDELAYEDEXPANSION
- set n=0&set _#=^"&set "stmp=%1"
- :asa
- if not "!stmp:~%n%,1!"=="" set/a n+=1&goto asa
- if "!stmp:~0,1!"=="!_#!" set/a n-=2
- ENDLOCAL&set "lenc=%n%"
- goto :EOF
- rem End_lenc
-
- rem 删除数字串两端0的子程序,三个参数:%2 为待处理的数字串;%1=l时删除数字串左端的0,%1=a时删除两端的0
- rem 其他值时删除右端的0;%3 为变量名,保存处理完的字串。用法:Call :_dez %1=l|r|a [%2=String [%3=var]]
- :_dez
- SETLOCAL ENABLEDELAYEDEXPANSION
- set str=%2&if "%3"=="" (set var=dez) else set var=%3
- if "%1"=="l" (set ts1=0,1&set tss=1) else set ts1=-1&set tss=0,-1
- :loopz
- if "!str:~%ts1%!"=="0" set str=!str:~%tss%!&goto :loopz
- if "%1"=="a" if "!ts1!"=="-1" set ts1=0,1&set tss=1&goto :loopz
- ENDLOCAL&set %var%=%str%&goto :EOF
- rem End_dez
-
- rem ---------------------------------------------------All End
复制代码 -----------------------------------------------------------------------------------
另附除法计算部分,仅支持整数输入
用法 call :_div 被除数 除数 [保留小数位,如精度不够则不保留]
返回结果 保存在变量quo中
例:- call :_div 5 3 3
- echo 5÷3 结果 %quo%
- rem 5除以3 保留3位小数
- call :_div 16 9
- echo 16÷9 结果 %quo%
- rem 16除以9 能算几位算几位
- pause:goto :eof
-
- rem 除法计算
- :_div
- if "%1"=="" echo 请输入被除数(参数 %%^1)&goto :EOF
- if "%2"=="" echo 请输入除数(参数 %%^2)&goto :EOF
- SETLOCAL ENABLEDELAYEDEXPANSION
- set Maxd=2147483647&set scp=0&set ded=%1&set dvr=%2&set quo=&set psc=%3
- if "%psc%"=="" set psc=%Maxd%
- if %dvr% equ 0 ENDLOCAL&echo 错误,除数为零!&goto :EOF
- if %ded% equ 0 ENDLOCAL&set quo=0&goto :EOF
- if "%ded%"=="%1" (if not "%dvr%"=="%2" ENDLOCAL&echo 参数 %%^2 输入错误或数值超限&goto :EOF)^
- else (echo 参数 %%^1 输入错误或数值超限
- if not "%dvr%"=="%2" ENDLOCAL&echo 参数 %%^2 输入错误或数值超限&goto :EOF)
- :divbg
- set/a quo=ded/dvr, rdd=quo*dvr
- if %rdd% neq %ded% if %ded% leq %Maxd:~0,-1% (
- if %scp% lss %psc% set ded=%ded%0&set/a scp+=1&goto :divbg
- )
- if %quo% equ 0 ENDLOCAL&set quo=0&goto :EOF
- if %scp% neq 0 if "!quo:~-%scp%!"=="!quo!" (
- set quo=00000000%quo%&set quo=0.!quo:~-%scp%!)^
- else set quo=!quo:~0,-%scp%!.!quo:~-%scp%!
- ENDLOCAL&set quo=%quo%&goto :EOF
复制代码
|