标题: [数值计算] 批处理实现浮点运算 [打印本页]
作者: buyiyang 时间: 2023-10-29 20:17 标题: 批处理实现浮点运算
本帖最后由 buyiyang 于 2023-11-2 18:39 编辑
批处理不能进行浮点运算是一大憾事,便起念写一个算法支持浮点,已经写了加法和乘法,加法比较简单,不限位数,乘法是通过二进制进行计算的,会有一定误差,同样不限位数。分享一下,望指教。
更新:添加了除法和求平方根,限制位数。
因帖子字数限制,分为两部分,此为第一部分,三楼为第二部分。- @echo off
- set "input=%~1"
- if "%input%"=="" echo,输入为空&exit /b
- set "input=%input: =%"
- if "%input%"=="" echo,输入为空&exit /b
- setlocal enabledelayedexpansion
- for /f "tokens=1-2 delims=+-*/" %%i in ("%input%") do (
- if not "%%j"=="" (set "p1=%%i"&set "p2=%%j") else set "p1=%%i"
- for /f "tokens=1-2 delims=0123456789." %%i in ("%input%") do set "op=%%i%%j"
- if "!op!"=="+" (call :add "!p1!" "!p2!"&echo,!add_result!) else if "!op!"=="-" (
- echo,减法) else if "!op!"=="*" (call :mul "!p1!" "!p2!"&echo,!mul_result!) else if "!op!"=="/" (
- call :div "!p1!" "!p2!"&echo,!quo_result!) else if "!op!"=="" (call :sqrt "!p1!"&echo,!sqrt_result!) else (echo,操作符错误)
- )
- exit /b
-
- :add
- setlocal
- for /f "tokens=1-2 delims=." %%i in ("%~1") do (
- set "p1_int=%%i"
- if "%%j"=="" (set /a p1_fd=0) else set "p1_fd=%%j"
- )
- for /f "tokens=1-2 delims=." %%i in ("%~2") do (
- set "p2_int=%%i"
- if "%%j"=="" (set /a p2_fd=0) else set "p2_fd=%%j"
- )
-
- call :strlen "%p1_fd%"
- set /a p1_fd_len=%len%
- call :strlen "%p2_fd%"
- set /a p2_fd_len=%len%
- if %p1_fd_len% geq %p2_fd_len% (set /a fd_len_max=p1_fd_len) else set /a fd_len_max=p2_fd_len
- set "zero_fill="
- for /l %%i in (1,1,%fd_len_max%) do set "zero_fill=!zero_fill!0"
- set "p1_fd=%p1_fd%%zero_fill%"&set "p1_fd=!p1_fd:~0,%fd_len_max%!"
- set "p2_fd=%p2_fd%%zero_fill%"&set "p2_fd=!p2_fd:~0,%fd_len_max%!"
- set /a carry=0
- set "fd_dec="
- for /l %%i in (-1,-1,-%fd_len_max%) do (
- set /a dec_place=!p1_fd:~%%i,1!+!p2_fd:~%%i,1!+!carry!
- if !dec_place! geq 10 (set /a carry=dec_place/10,dec_place=dec_place-10) else set /a carry=0
- set "fd_dec=!dec_place!!fd_dec!"
- )
-
- call :strlen "%p1_int%"
- set /a p1_int_len=%len%
- call :strlen "%p2_int%"
- set /a p2_int_len=%len%
- if %p1_int_len% geq %p2_int_len% (set /a int_len_max=p1_int_len) else set /a int_len_max=p2_int_len
- set "zero_fill="
- for /l %%i in (1,1,%int_len_max%) do set "zero_fill=!zero_fill!0"
- set "p1_int=%zero_fill%%p1_int%"&set "p1_int=!p1_int:~-%int_len_max%!"
- set "p2_int=%zero_fill%%p2_int%"&set "p2_int=!p2_int:~-%int_len_max%!"
- set "int_dec="
- for /l %%i in (-1,-1,-%int_len_max%) do (
- set /a dec_place=!p1_int:~%%i,1!+!p2_int:~%%i,1!+!carry!
- if !dec_place! geq 10 (set /a carry=dec_place/10,dec_place=dec_place-10) else set /a carry=0
- set "int_dec=!dec_place!!int_dec!"
- )
- if %carry% gtr 0 set "int_dec=%carry%%int_dec%"
- if %int_dec% equ 0 (set /a int_dec=0) else for /f "tokens=* delims=0" %%i in ("%int_dec%") do set "int_dec=%%i"
- endlocal&set "add_result=%int_dec%.%fd_dec%"&set "int_dec=%int_dec%"&set "fd_dec=%fd_dec%"
- goto :eof
-
- :mul
- setlocal
- for /f "tokens=1-2 delims=." %%i in ("%~1") do (
- set "p1_int=%%i"
- if "%%j"=="" (set /a p1_fd=0) else set "p1_fd=%%j"
- )
- for /f "tokens=1-2 delims=." %%i in ("%~2") do (
- set "p2_int=%%i"
- if "%%j"=="" (set /a p2_fd=0) else set "p2_fd=%%j"
- )
- call :int2bin "%p1_int%"
- set "p1_int_bin=%int_bin%"
- call :int2bin "%p2_int%"
- set "p2_int_bin=%int_bin%"
-
- call :fd2bin "%p1_fd%"
- set "p1_fd_bin=%fd_bin%"
- call :fd2bin "%p2_fd%"
- set "p2_fd_bin=%fd_bin%"
-
- set "p1_conbin=%p1_int_bin%%p1_fd_bin%"
- set "p2_conbin=%p2_int_bin%%p2_fd_bin%"
- rem echo,%p1_conbin%
- rem echo,%p2_conbin%
- set /a acc=0
- call :strlen "%p1_conbin%"
- set /a p1_conbin_len=%len%
- set "p2_conbin_shift=%p2_conbin%"
- for /l %%i in (-1,-1,-%p1_conbin_len%) do (
- if "!p1_conbin:~%%i,1!"=="1" (call :add_bin "!acc!" "!p2_conbin_shift!")
- set "acc=!add_bin_result!"
- set "p2_conbin_shift=!p2_conbin_shift!0"
- )
- set "acc=%acc:~0,-32%"
- call :strlen "%acc%"
- set /a acc_len=%len%
- if %acc_len% lss 33 (
- set "zero_fill="
- for /l %%i in (1,1,33) do set "zero_fill=!zero_fill!0"
- set "acc=!zero_fill!!acc!"
- )
- set "acc_fd=%acc:~-32%"
- set "acc_int=%acc:~0,-32%"
- if %acc_int% equ 0 (set /a acc_int=0) else (
- for /f "tokens=* delims=0" %%i in ("%acc_int%") do set "acc_int=%%i"
- )
- set "acc_int_fd=%acc_int%.%acc_fd%"
- rem echo,%acc_int_fd%
- call :bin2dec "%acc_int%" "%acc_fd%"
- endlocal&set "mul_result=%bin2dec_result%"
- goto :eof
-
- :div
- setlocal
- for /f "tokens=1-2 delims=." %%i in ("%~1") do (
- set /a p1_int_div=%%i
- if "%%j"=="" (set /a p1_fd_div_len=0) else (
- set "p1_fd_div=%%j"
- call :strlen "%%j"
- set /a p1_fd_div_len=len
- )
- )
- for /f "tokens=* delims=0" %%i in ("%p1_fd_div%") do if %%i equ 0 (set /a p1_fd_div=0) else set /a p1_fd_div=%%i
- for /f "tokens=1-2 delims=." %%i in ("%~2") do (
- call :strlen "%%j"
- set /a p2_div_fd_len=len
- set "p2_div=%%i%%j"
- )
- for /f "tokens=* delims=0" %%i in ("%p2_div%") do set /a p2_div=%%i
- set /a divisor=p2_div,divisor_offset=p2_div_fd_len
- set "int_quo="
- set /a int_div_offset=divisor_offset
- for /l %%i in (1,1,32) do (
- if !p1_int_div! lss %divisor% (
- set /a p1_int_div*=10,div_q=0
- set "int_quo=!int_quo!!div_q!"
- if %%i equ 1 (call :strlen "!div_q!"&set /a or_len=len)
- ) else (
- set /a div_q=!p1_int_div!/%divisor%,div_mod=!p1_int_div!%%%divisor%
- if %%i equ 1 (call :strlen "!div_q!"&set /a or_len=len)
- set "int_quo=!int_quo!!div_q!"
- set "p1_int_div=!div_mod!0"
- if !div_q! equ 0 goto :int_div_next
- )
- )
- :int_div_next
- set /a int_div_offset+=or_len
- if %int_div_offset% gtr 0 (
- for /f "tokens=* delims=0" %%i in ("!int_quo:~0,%int_div_offset%!") do if "%%i"=="" (set "int_quo_int=0") else set "int_quo_int=%%i"
- set "int_quo_fd=!int_quo:~%int_div_offset%!"
- ) else (
- for /l %%i in (-1,-1,%int_div_offset%) do set "int_quo=0!int_quo!"
- set "int_quo_int=!int_quo:~0,1!"
- set "int_quo_fd=!int_quo:~1!"
- )
- set "int_quo_result=%int_quo_int%.%int_quo_fd%"
- set "fd_quo="
- set /a dividend=p1_fd_div,fd_div_offset=divisor_offset-p1_fd_div_len-1
- for /l %%i in (1,1,32) do (
- if !dividend! lss %divisor% (
- set /a dividend*=10,div_q=0
- set "fd_quo=!fd_quo!!div_q!"
- if %%i equ 1 (call :strlen "!div_q!"&set /a or_len=len)
- ) else (
- set /a div_q=!dividend!/%divisor%,div_mod=!dividend!%%%divisor%
- if %%i equ 1 (call :strlen "!div_q!"&set /a or_len=len)
- set "fd_quo=!fd_quo!!div_q!"
- set "dividend=!div_mod!0"
- if !div_mod! equ 0 goto :fd_div_next
- )
- )
- :fd_div_next
- set /a fd_div_offset+=or_len
- if %fd_div_offset% gtr 0 (set /a fd_div_offset+=1)
- if %fd_div_offset% gtr 0 (
- for /f "tokens=* delims=0" %%i in ("!fd_quo:~0,%fd_div_offset%!") do if "%%i"=="" (set "fd_quo_int=0") else set "fd_quo_int=%%i"
- set "fd_quo_fd=!fd_quo:~%fd_div_offset%!"
- ) else (
- for /l %%i in (-1,-1,%fd_div_offset%) do set "fd_quo=0!fd_quo!"
- set "fd_quo_int=!fd_quo:~0,1!"
- set "fd_quo_fd=!fd_quo:~1!"
- )
- set "fd_quo_result=%fd_quo_int%.%fd_quo_fd%"
- call :add "%int_quo_result%" "%fd_quo_result%"
- endlocal&set "quo_result=%add_result%"
- goto :eof
复制代码
用法:- R:\>byy.bat 202.3+1.029
- 203.329
-
- R:\>byy.bat 202.3*1.029
- 208.16669997223652899265289306640625
-
- R:\>byy.bat 20231102.1102
- 4497.8997651170000000000000000000000
-
- R:\>byy.bat 2023.1102/1102
- 1.8358531760435571687840290381125
复制代码
作者: Batcher 时间: 2023-10-29 21:06
这里有几个浮点数计算的代码,感兴趣的朋友们可以一起看看:
http://bbs.bathome.net/thread-3322-1-1.html
http://bbs.bathome.net/thread-3372-1-1.html
作者: buyiyang 时间: 2023-11-2 18:38
第二部分- :sqrt
- for /f "tokens=1-2 delims=." %%i in ("%~1") do (
- set "p1_int_sqrt=%%i"
- if "%%j"=="" (set /a p1_fd_sqrt=0) else set "p1_fd_sqrt=%%j"
- )
- call :int2bin "%p1_int_sqrt%"
- set "p1_int_sqrt_bin=%int_bin%"
- call :fd2bin "%p1_fd_sqrt%"
- set "p1_fd_sqrt_bin=%fd_bin%"
- set "p1_sqrt_bin=%p1_int_sqrt_bin%%p1_fd_sqrt_bin%"
- call :strlen "%p1_sqrt_bin%"&set /a before=len
- for /f "tokens=* delims=0" %%i in ("%p1_sqrt_bin%") do set "p1_sqrt_bin=%%i"&call :strlen "%%i"
- set /a zero_offset=len-before
- call :strlen "!p1_int_sqrt_bin!"
- set /a p1_sqrt_offset=len-1+zero_offset,e_de=127+p1_sqrt_offset
- call ::int2bin "%e_de%"
- set "e_bin=%int_bin%"
- set "zero_fill="
- for /l %%i in (1,1,8) do set "zero_fill=!zero_fill!0"
- set "e_bin=%zero_fill%%e_bin%"
- set "e_bin=%e_bin:~-8%"
- set "m=%p1_sqrt_bin:~1%"
- set "m=%m:~0,23%"
- set "p1_ieee=0%e_bin%%m%"
- rem echo,%p1_ieee%
- call :sub_bin "1011111001101110101101010000110" "0%p1_ieee:~0,-1%"
- call :bin2dec "%sub_bin_result:~1,8%"
- set /a sub_bin_result_offset=int_sum-127
- set "sub_bin_result_m=1%sub_bin_result:~-23%"
- if %sub_bin_result_offset% gtr 0 (set /a sub_bin_result_offset+=1)
- if %sub_bin_result_offset% gtr 0 (
- set "sub_bin_result_int=!sub_bin_result_m:~0,%sub_bin_result_offset%!"
- set "sub_bin_result_fd=!sub_bin_result_m:~%sub_bin_result_offset%!"
- ) else (
- for /l %%i in (-1,-1,%sub_bin_result_offset%) do set "sub_bin_result_m=0!sub_bin_result_m!"
- set "sub_bin_result_int=!sub_bin_result_m:~0,1!"
- set "sub_bin_result_fd=!sub_bin_result_m:~1!"
- )
- call :bin2dec "%sub_bin_result_int%" "%sub_bin_result_fd%"
- set "sqrt_result1=%bin2dec_result%"
- call :div "1" "%sqrt_result1:~0,9%"
- set "sqrt_result0=%quo_result%"
- rem echo,%sqrt_result0%
- for /f "tokens=1-2 delims=." %%i in ("%sqrt_result0%") do set "j=%%j"&set "sqrt_result0=%%i.!j:~0,9!"
- call :div "%sqrt_result0%" "2"
- set "x=%quo_result%"
- call :add "%~1" "0"
- for /f "tokens=1-2 delims=." %%i in ("%add_result%") do set "j=%%j"&set "pre_y=%%i.!j:~0,9!"
- call :div "%pre_y%" "%sqrt_result0:~0,9%"
- for /f "tokens=1-2 delims=." %%i in ("%quo_result%") do set "j=%%j"&set "y=%%i.!j:~0,9!"
- call :div "%y%" "2"
- set "y=%quo_result%"
- call :add "%x%" "%y%"
- set "sqrt_result00=%add_result%"
- for /f "tokens=1-2 delims=." %%i in ("%sqrt_result00%") do set "j=%%j"&set "sqrt_result00=%%i.!j:~0,9!"
- call :div "%sqrt_result00%" "2"
- set "x=%quo_result%"
- call :add "%~1" "0"
- for /f "tokens=1-2 delims=." %%i in ("%add_result%") do set "j=%%j"&set "pre_y=%%i.!j:~0,9!"
- call :div "%pre_y%" "%sqrt_result00:~0,9%"
- for /f "tokens=1-2 delims=." %%i in ("%quo_result%") do set "j=%%j"&set "y=%%i.!j:~0,9!"
- call :div "%y%" "2"
- set "y=%quo_result%"
- call :add "%x%" "%y%"
- set "sqrt_result=%add_result%"
- goto :eof
-
- :strlen
- set "s=%~1"
- set "zz=0 1 2 3 4 5 6 7 8 9 a b c d e f"
- if not defined list for %%a in (%zz%)do for %%b in (%zz%)do set list=!list!%%a%%b
- set "s=!list!!s!!s!"
- set /a len=0X%s:~-512,2%
- goto :eof
-
- :int2bin
- set /a i=%~1
- set "int_bin="
- if %i% gtr 0 (set /a s=0) else if %i% lss 0 (set /a s=1,i=-i) else (set /a int_bin=0,s=0&goto :eof)
- for /l %%i in (1,1,32) do if !i! neq 1 (
- set /a ii=i,i=i/2,bin=ii%%2
- set int_bin=!bin!!int_bin!) else (
- set int_bin=1!int_bin!
- goto :eof
- )
- goto :eof
-
- :fd2bin
- if %~1 equ 0 (
- set "zero_fill="
- for /l %%i in (1,1,32) do set "zero_fill=!zero_fill!0"
- set "fd_bin=!zero_fill!"
- goto :eof
- )
- set "fd_bin="
- set "f=0.%~1"
- for /l %%i in (1,1,32) do (
- call :add "!f!" "!f!"
- if !int_dec! geq 1 (set fd_bin=!fd_bin!1) else set fd_bin=!fd_bin!0
- set "f=0.!fd_dec!"
- )
- goto :eof
-
- :add_bin
- set "p1_bin=%~1"
- set "p2_bin=%~2"
- set "bin_result="
- set /a carry=0
- call :strlen "%p1_bin%"
- set /a p1_bin_len=%len%
- call :strlen "%p2_bin%"
- set /a p2_bin_len=%len%
- if %p1_bin_len% geq %p2_bin_len% (set /a bin_len_max=p1_bin_len+1) else set /a bin_len_max=p2_bin_len+1
- for /l %%i in (-1,-1,-%bin_len_max%) do (
- if %%i lss -%p1_bin_len% (set /a p1_bin_place=0) else set "p1_bin_place=!p1_bin:~%%i,1!"
- if %%i lss -%p2_bin_len% (set /a p2_bin_place=0) else set "p2_bin_place=!p2_bin:~%%i,1!"
- set /a bin_place=!p1_bin_place!+!p2_bin_place!+!carry!
- if !bin_place! geq 2 (set /a carry=bin_place/2,bin_place=bin_place-2) else set /a carry=0
- set "bin_result=!bin_place!!bin_result!"
- )
- set "add_bin_result=%bin_result%"
- goto :eof
-
- :bin2dec
- set "int_bin=%~1"
- set "fd_bin=%~2"
- set /a int_sum=0
- if "%~1"=="" goto :fd_bin2dec
- call :strlen "%int_bin%"
- set /a int_len=len
- set /a bin2dec_n=1,int_sum=0
- for /l %%i in (-1,-1,-%int_len%) do (
- if "!int_bin:~%%i,1!"=="1" (
- call :add "!int_sum!" "!bin2dec_n!"
- set "int_sum=!add_result!"
- )
- call :add "!bin2dec_n!" "!bin2dec_n!"
- set "bin2dec_n=!add_result!"
- )
- if "%~2"=="" goto :eof
- :fd_bin2dec
- set "bin2dec_half=0.5"
- set /a fd_sum=0
- for /l %%i in (0,1,32) do if not "!fd_bin:~%%i,1!"=="" (
- if "!fd_bin:~%%i,1!"=="1" (
- call :add "!fd_sum!" "!bin2dec_half!"
- set "fd_sum=!add_result!"
- )
- call :fd_half "!bin2dec_half!"
- set "bin2dec_half=!fd_half!"
- )
- call :add "%int_sum%" "%fd_sum%"
- set "bin2dec_result=%add_result%"
- goto :eof
-
- :sub_bin
- set "sub_bin_p1=%~1"
- set "sub_bin_p2=%~2"
- set "sub_bin_result="
- set /a sub_bin_carry=0
- for /l %%i in (-1,-1,-32) do (
- set /a sub_bin_p1_place=!sub_bin_p1:~%%i,1!+sub_bin_carry
- set "sub_bin_p2_place=!sub_bin_p2:~%%i,1!"
- if !sub_bin_p1_place! lss !sub_bin_p2_place! (set /a sub_bin_p1_place+=2,sub_bin_carry=-1
- ) else set /a sub_bin_carry=0
- set /a diffe=sub_bin_p1_place-sub_bin_p2_place
- set "sub_bin_result=!diffe!!sub_bin_result!"
- )
- goto :eof
-
- :fd_half
- set "fd_half="
- set "one=%~1"
- set "one=%one:*.=%"
- for /l %%i in (0,1,32) do (
- if "!one:~%%i,1!"=="" (set "one_i=!pre!0") else set "one_i=!pre!!one:~%%i,1!"
- set /a one_ii=one_i,one_i=one_i/2,one_mod=one_ii%%2
- if "!one_mod!"=="0" (set "pre=") else set /a pre=one_mod
- set "fd_half=!fd_half!!one_i!"
- if "!one:~%%i,1!"=="" (if "!one_mod!"=="0" goto :fd_half_next)
- )
- :fd_half_next
- set "fd_half=0.%fd_half%"
- goto :eof
复制代码
欢迎光临 批处理之家 (http://www.bathome.net/) |
Powered by Discuz! 7.2 |