[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖

[数值计算] 批处理实现浮点运算

本帖最后由 buyiyang 于 2023-11-2 18:39 编辑

批处理不能进行浮点运算是一大憾事,便起念写一个算法支持浮点,已经写了加法和乘法,加法比较简单,不限位数,乘法是通过二进制进行计算的,会有一定误差,同样不限位数。分享一下,望指教。
更新:添加了除法和求平方根,限制位数。
因帖子字数限制,分为两部分,此为第一部分,三楼为第二部分。
  1. @echo off
  2. set "input=%~1"
  3. if "%input%"=="" echo,输入为空&exit /b
  4. set "input=%input: =%"
  5. if "%input%"=="" echo,输入为空&exit /b
  6. setlocal enabledelayedexpansion
  7. for /f "tokens=1-2 delims=+-*/" %%i in ("%input%") do (
  8.     if not "%%j"=="" (set "p1=%%i"&set "p2=%%j") else set "p1=%%i"
  9.     for /f "tokens=1-2 delims=0123456789." %%i in ("%input%") do set "op=%%i%%j"
  10.     if "!op!"=="+" (call :add "!p1!" "!p2!"&echo,!add_result!) else if "!op!"=="-" (
  11.     echo,减法) else if "!op!"=="*" (call :mul "!p1!" "!p2!"&echo,!mul_result!) else if "!op!"=="/" (
  12.     call :div "!p1!" "!p2!"&echo,!quo_result!) else if "!op!"=="" (call :sqrt "!p1!"&echo,!sqrt_result!) else (echo,操作符错误)
  13.     )
  14. exit /b
  15. :add
  16. setlocal
  17. for /f "tokens=1-2 delims=." %%i in ("%~1") do (
  18.     set "p1_int=%%i"
  19.     if "%%j"=="" (set /a p1_fd=0) else set "p1_fd=%%j"
  20.     )
  21. for /f "tokens=1-2 delims=." %%i in ("%~2") do (
  22.     set "p2_int=%%i"
  23.     if "%%j"=="" (set /a p2_fd=0) else set "p2_fd=%%j"
  24.     )
  25. call :strlen "%p1_fd%"
  26. set /a p1_fd_len=%len%
  27. call :strlen "%p2_fd%"
  28. set /a p2_fd_len=%len%
  29. 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
  30. set "zero_fill="
  31. for /l %%i in (1,1,%fd_len_max%) do set "zero_fill=!zero_fill!0"
  32. set "p1_fd=%p1_fd%%zero_fill%"&set "p1_fd=!p1_fd:~0,%fd_len_max%!"
  33. set "p2_fd=%p2_fd%%zero_fill%"&set "p2_fd=!p2_fd:~0,%fd_len_max%!"
  34. set /a carry=0
  35. set "fd_dec="
  36. for /l %%i in (-1,-1,-%fd_len_max%) do (
  37.     set /a dec_place=!p1_fd:~%%i,1!+!p2_fd:~%%i,1!+!carry!
  38.     if !dec_place! geq 10 (set /a carry=dec_place/10,dec_place=dec_place-10) else set /a carry=0
  39.     set "fd_dec=!dec_place!!fd_dec!"
  40.     )
  41. call :strlen "%p1_int%"
  42. set /a p1_int_len=%len%
  43. call :strlen "%p2_int%"
  44. set /a p2_int_len=%len%
  45. 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
  46. set "zero_fill="
  47. for /l %%i in (1,1,%int_len_max%) do set "zero_fill=!zero_fill!0"
  48. set "p1_int=%zero_fill%%p1_int%"&set "p1_int=!p1_int:~-%int_len_max%!"
  49. set "p2_int=%zero_fill%%p2_int%"&set "p2_int=!p2_int:~-%int_len_max%!"
  50. set "int_dec="
  51. for /l %%i in (-1,-1,-%int_len_max%) do (
  52.     set /a dec_place=!p1_int:~%%i,1!+!p2_int:~%%i,1!+!carry!
  53.     if !dec_place! geq 10 (set /a carry=dec_place/10,dec_place=dec_place-10) else set /a carry=0
  54.     set "int_dec=!dec_place!!int_dec!"
  55.     )
  56. if %carry% gtr 0 set "int_dec=%carry%%int_dec%"
  57. 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"
  58. endlocal&set "add_result=%int_dec%.%fd_dec%"&set "int_dec=%int_dec%"&set "fd_dec=%fd_dec%"
  59. goto :eof
  60. :mul
  61. setlocal
  62. for /f "tokens=1-2 delims=." %%i in ("%~1") do (
  63.     set "p1_int=%%i"
  64.     if "%%j"=="" (set /a p1_fd=0) else set "p1_fd=%%j"
  65.     )
  66. for /f "tokens=1-2 delims=." %%i in ("%~2") do (
  67.     set "p2_int=%%i"
  68.     if "%%j"=="" (set /a p2_fd=0) else set "p2_fd=%%j"
  69.     )
  70. call :int2bin "%p1_int%"
  71. set "p1_int_bin=%int_bin%"
  72. call :int2bin "%p2_int%"
  73. set "p2_int_bin=%int_bin%"
  74. call :fd2bin "%p1_fd%"
  75. set "p1_fd_bin=%fd_bin%"
  76. call :fd2bin "%p2_fd%"
  77. set "p2_fd_bin=%fd_bin%"
  78. set "p1_conbin=%p1_int_bin%%p1_fd_bin%"
  79. set "p2_conbin=%p2_int_bin%%p2_fd_bin%"
  80. rem echo,%p1_conbin%
  81. rem echo,%p2_conbin%
  82. set /a acc=0
  83. call :strlen "%p1_conbin%"
  84. set /a p1_conbin_len=%len%
  85. set "p2_conbin_shift=%p2_conbin%"
  86. for /l %%i in (-1,-1,-%p1_conbin_len%) do (
  87.     if "!p1_conbin:~%%i,1!"=="1" (call :add_bin "!acc!" "!p2_conbin_shift!")
  88.     set "acc=!add_bin_result!"
  89.     set "p2_conbin_shift=!p2_conbin_shift!0"
  90.     )
  91. set "acc=%acc:~0,-32%"
  92. call :strlen "%acc%"
  93. set /a acc_len=%len%
  94. if %acc_len% lss 33 (
  95.     set "zero_fill="
  96.     for /l %%i in (1,1,33) do set "zero_fill=!zero_fill!0"
  97.     set "acc=!zero_fill!!acc!"
  98.     )
  99. set "acc_fd=%acc:~-32%"
  100. set "acc_int=%acc:~0,-32%"
  101. if %acc_int% equ 0 (set /a acc_int=0) else (
  102.     for /f "tokens=* delims=0" %%i in ("%acc_int%") do set "acc_int=%%i"
  103.     )
  104. set "acc_int_fd=%acc_int%.%acc_fd%"
  105. rem echo,%acc_int_fd%
  106. call :bin2dec "%acc_int%" "%acc_fd%"
  107. endlocal&set "mul_result=%bin2dec_result%"
  108. goto :eof
  109. :div
  110. setlocal
  111. for /f "tokens=1-2 delims=." %%i in ("%~1") do (
  112.     set /a p1_int_div=%%i
  113.     if "%%j"=="" (set /a p1_fd_div_len=0) else (
  114.         set "p1_fd_div=%%j"
  115.         call :strlen "%%j"
  116.         set /a p1_fd_div_len=len
  117.         )
  118.     )
  119. 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
  120. for /f "tokens=1-2 delims=." %%i in ("%~2") do (
  121.     call :strlen "%%j"
  122.     set /a p2_div_fd_len=len
  123.     set "p2_div=%%i%%j"
  124.     )
  125. for /f "tokens=* delims=0" %%i in ("%p2_div%") do set /a p2_div=%%i
  126. set /a divisor=p2_div,divisor_offset=p2_div_fd_len
  127. set "int_quo="
  128. set /a int_div_offset=divisor_offset
  129. for /l %%i in (1,1,32) do (
  130.     if !p1_int_div! lss %divisor% (
  131.         set /a p1_int_div*=10,div_q=0
  132.         set "int_quo=!int_quo!!div_q!"
  133.         if %%i equ 1 (call :strlen "!div_q!"&set /a or_len=len)
  134.         ) else (
  135.         set /a div_q=!p1_int_div!/%divisor%,div_mod=!p1_int_div!%%%divisor%
  136.         if %%i equ 1 (call :strlen "!div_q!"&set /a or_len=len)
  137.         set "int_quo=!int_quo!!div_q!"
  138.         set "p1_int_div=!div_mod!0"
  139.         if !div_q! equ 0 goto :int_div_next
  140.         )
  141.     )
  142. :int_div_next
  143. set /a int_div_offset+=or_len
  144. if %int_div_offset% gtr 0 (
  145. 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"
  146. set "int_quo_fd=!int_quo:~%int_div_offset%!"
  147. ) else (
  148. for /l %%i in (-1,-1,%int_div_offset%) do set "int_quo=0!int_quo!"
  149. set "int_quo_int=!int_quo:~0,1!"
  150. set "int_quo_fd=!int_quo:~1!"
  151. )
  152. set "int_quo_result=%int_quo_int%.%int_quo_fd%"
  153. set "fd_quo="
  154. set /a dividend=p1_fd_div,fd_div_offset=divisor_offset-p1_fd_div_len-1
  155. for /l %%i in (1,1,32) do (
  156.     if !dividend! lss %divisor% (
  157.         set /a dividend*=10,div_q=0
  158.         set "fd_quo=!fd_quo!!div_q!"
  159.         if %%i equ 1 (call :strlen "!div_q!"&set /a or_len=len)
  160.         ) else (
  161.         set /a div_q=!dividend!/%divisor%,div_mod=!dividend!%%%divisor%
  162.         if %%i equ 1 (call :strlen "!div_q!"&set /a or_len=len)
  163.         set "fd_quo=!fd_quo!!div_q!"
  164.         set "dividend=!div_mod!0"
  165.         if !div_mod! equ 0 goto :fd_div_next
  166.         )
  167.     )
  168. :fd_div_next
  169. set /a fd_div_offset+=or_len
  170. if %fd_div_offset% gtr 0 (set /a fd_div_offset+=1)
  171. if %fd_div_offset% gtr 0 (
  172. 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"
  173. set "fd_quo_fd=!fd_quo:~%fd_div_offset%!"
  174. ) else (
  175. for /l %%i in (-1,-1,%fd_div_offset%) do set "fd_quo=0!fd_quo!"
  176. set "fd_quo_int=!fd_quo:~0,1!"
  177. set "fd_quo_fd=!fd_quo:~1!"
  178. )
  179. set "fd_quo_result=%fd_quo_int%.%fd_quo_fd%"
  180. call :add "%int_quo_result%" "%fd_quo_result%"
  181. endlocal&set "quo_result=%add_result%"
  182. goto :eof
复制代码
用法:
  1. R:\>byy.bat 202.3+1.029
  2. 203.329
  3. R:\>byy.bat 202.3*1.029
  4. 208.16669997223652899265289306640625
  5. R:\>byy.bat 20231102.1102
  6. 4497.8997651170000000000000000000000
  7. R:\>byy.bat 2023.1102/1102
  8. 1.8358531760435571687840290381125
复制代码

第二部分
  1. :sqrt
  2. for /f "tokens=1-2 delims=." %%i in ("%~1") do (
  3.     set "p1_int_sqrt=%%i"
  4.     if "%%j"=="" (set /a p1_fd_sqrt=0) else set "p1_fd_sqrt=%%j"
  5.     )
  6. call :int2bin "%p1_int_sqrt%"
  7. set "p1_int_sqrt_bin=%int_bin%"
  8. call :fd2bin "%p1_fd_sqrt%"
  9. set "p1_fd_sqrt_bin=%fd_bin%"
  10. set "p1_sqrt_bin=%p1_int_sqrt_bin%%p1_fd_sqrt_bin%"
  11. call :strlen "%p1_sqrt_bin%"&set /a before=len
  12. for /f "tokens=* delims=0" %%i in ("%p1_sqrt_bin%") do set "p1_sqrt_bin=%%i"&call :strlen "%%i"
  13. set /a zero_offset=len-before
  14. call :strlen "!p1_int_sqrt_bin!"
  15. set /a p1_sqrt_offset=len-1+zero_offset,e_de=127+p1_sqrt_offset
  16. call ::int2bin "%e_de%"
  17. set "e_bin=%int_bin%"
  18. set "zero_fill="
  19. for /l %%i in (1,1,8) do set "zero_fill=!zero_fill!0"
  20. set "e_bin=%zero_fill%%e_bin%"
  21. set "e_bin=%e_bin:~-8%"
  22. set "m=%p1_sqrt_bin:~1%"
  23. set "m=%m:~0,23%"
  24. set "p1_ieee=0%e_bin%%m%"
  25. rem echo,%p1_ieee%
  26. call :sub_bin "1011111001101110101101010000110" "0%p1_ieee:~0,-1%"
  27. call :bin2dec "%sub_bin_result:~1,8%"
  28. set /a sub_bin_result_offset=int_sum-127
  29. set "sub_bin_result_m=1%sub_bin_result:~-23%"
  30. if %sub_bin_result_offset% gtr 0 (set /a sub_bin_result_offset+=1)
  31. if %sub_bin_result_offset% gtr 0 (
  32. set "sub_bin_result_int=!sub_bin_result_m:~0,%sub_bin_result_offset%!"
  33. set "sub_bin_result_fd=!sub_bin_result_m:~%sub_bin_result_offset%!"
  34. ) else (
  35. for /l %%i in (-1,-1,%sub_bin_result_offset%) do set "sub_bin_result_m=0!sub_bin_result_m!"
  36. set "sub_bin_result_int=!sub_bin_result_m:~0,1!"
  37. set "sub_bin_result_fd=!sub_bin_result_m:~1!"
  38. )
  39. call :bin2dec "%sub_bin_result_int%" "%sub_bin_result_fd%"
  40. set "sqrt_result1=%bin2dec_result%"
  41. call :div "1" "%sqrt_result1:~0,9%"
  42. set "sqrt_result0=%quo_result%"
  43. rem echo,%sqrt_result0%
  44. for /f "tokens=1-2 delims=." %%i in ("%sqrt_result0%") do set "j=%%j"&set "sqrt_result0=%%i.!j:~0,9!"
  45. call :div "%sqrt_result0%" "2"
  46. set "x=%quo_result%"
  47. call :add "%~1" "0"
  48. for /f "tokens=1-2 delims=." %%i in ("%add_result%") do set "j=%%j"&set "pre_y=%%i.!j:~0,9!"
  49. call :div "%pre_y%" "%sqrt_result0:~0,9%"
  50. for /f "tokens=1-2 delims=." %%i in ("%quo_result%") do set "j=%%j"&set "y=%%i.!j:~0,9!"
  51. call :div "%y%" "2"
  52. set "y=%quo_result%"
  53. call :add "%x%" "%y%"
  54. set "sqrt_result00=%add_result%"
  55. for /f "tokens=1-2 delims=." %%i in ("%sqrt_result00%") do set "j=%%j"&set "sqrt_result00=%%i.!j:~0,9!"
  56. call :div "%sqrt_result00%" "2"
  57. set "x=%quo_result%"
  58. call :add "%~1" "0"
  59. for /f "tokens=1-2 delims=." %%i in ("%add_result%") do set "j=%%j"&set "pre_y=%%i.!j:~0,9!"
  60. call :div "%pre_y%" "%sqrt_result00:~0,9%"
  61. for /f "tokens=1-2 delims=." %%i in ("%quo_result%") do set "j=%%j"&set "y=%%i.!j:~0,9!"
  62. call :div "%y%" "2"
  63. set "y=%quo_result%"
  64. call :add "%x%" "%y%"
  65. set "sqrt_result=%add_result%"
  66. goto :eof
  67. :strlen
  68. set "s=%~1"
  69. set "zz=0 1 2 3 4 5 6 7 8 9 a b c d e f"
  70. if not defined list for %%a in (%zz%)do for %%b in (%zz%)do set list=!list!%%a%%b
  71. set "s=!list!!s!!s!"
  72. set /a len=0X%s:~-512,2%
  73. goto :eof
  74. :int2bin
  75. set /a i=%~1
  76. set "int_bin="
  77. 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)
  78. for /l %%i in (1,1,32) do if !i! neq 1 (
  79.     set /a ii=i,i=i/2,bin=ii%%2
  80.     set int_bin=!bin!!int_bin!) else (
  81.     set int_bin=1!int_bin!
  82.     goto :eof
  83.     )
  84. goto :eof
  85. :fd2bin
  86. if %~1 equ 0 (
  87.     set "zero_fill="
  88.     for /l %%i in (1,1,32) do set "zero_fill=!zero_fill!0"
  89.     set "fd_bin=!zero_fill!"
  90.     goto :eof
  91.     )
  92. set "fd_bin="
  93. set "f=0.%~1"
  94. for /l %%i in (1,1,32) do (
  95.     call :add "!f!" "!f!"
  96.     if !int_dec! geq 1 (set fd_bin=!fd_bin!1) else set fd_bin=!fd_bin!0
  97.     set "f=0.!fd_dec!"
  98.     )
  99. goto :eof
  100. :add_bin
  101. set "p1_bin=%~1"
  102. set "p2_bin=%~2"
  103. set "bin_result="
  104. set /a carry=0
  105. call :strlen "%p1_bin%"
  106. set /a p1_bin_len=%len%
  107. call :strlen "%p2_bin%"
  108. set /a p2_bin_len=%len%
  109. 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
  110. for /l %%i in (-1,-1,-%bin_len_max%) do (
  111.     if %%i lss -%p1_bin_len% (set /a p1_bin_place=0) else set "p1_bin_place=!p1_bin:~%%i,1!"
  112.     if %%i lss -%p2_bin_len% (set /a p2_bin_place=0) else set "p2_bin_place=!p2_bin:~%%i,1!"
  113.     set /a bin_place=!p1_bin_place!+!p2_bin_place!+!carry!
  114.     if !bin_place! geq 2 (set /a carry=bin_place/2,bin_place=bin_place-2) else set /a carry=0
  115.     set "bin_result=!bin_place!!bin_result!"
  116.     )
  117. set "add_bin_result=%bin_result%"
  118. goto :eof
  119. :bin2dec
  120. set "int_bin=%~1"
  121. set "fd_bin=%~2"
  122. set /a int_sum=0
  123. if "%~1"=="" goto :fd_bin2dec
  124. call :strlen "%int_bin%"
  125. set /a int_len=len
  126. set /a bin2dec_n=1,int_sum=0
  127. for /l %%i in (-1,-1,-%int_len%) do (
  128.     if "!int_bin:~%%i,1!"=="1" (
  129.         call :add "!int_sum!" "!bin2dec_n!"
  130.         set "int_sum=!add_result!"
  131.         )
  132.     call :add "!bin2dec_n!" "!bin2dec_n!"
  133.     set "bin2dec_n=!add_result!"
  134.     )
  135. if "%~2"=="" goto :eof
  136. :fd_bin2dec
  137. set "bin2dec_half=0.5"
  138. set /a fd_sum=0
  139. for /l %%i in (0,1,32) do if not "!fd_bin:~%%i,1!"=="" (
  140.     if "!fd_bin:~%%i,1!"=="1" (
  141.         call :add "!fd_sum!" "!bin2dec_half!"
  142.         set "fd_sum=!add_result!"
  143.         )
  144.     call :fd_half "!bin2dec_half!"
  145.     set "bin2dec_half=!fd_half!"
  146.     )
  147. call :add "%int_sum%" "%fd_sum%"
  148. set "bin2dec_result=%add_result%"
  149. goto :eof
  150. :sub_bin
  151. set "sub_bin_p1=%~1"
  152. set "sub_bin_p2=%~2"
  153. set "sub_bin_result="
  154. set /a sub_bin_carry=0
  155. for /l %%i in (-1,-1,-32) do (
  156.     set /a sub_bin_p1_place=!sub_bin_p1:~%%i,1!+sub_bin_carry
  157.     set "sub_bin_p2_place=!sub_bin_p2:~%%i,1!"
  158.     if !sub_bin_p1_place! lss !sub_bin_p2_place! (set /a sub_bin_p1_place+=2,sub_bin_carry=-1
  159.     ) else set /a sub_bin_carry=0
  160.     set /a diffe=sub_bin_p1_place-sub_bin_p2_place
  161.     set "sub_bin_result=!diffe!!sub_bin_result!"
  162.     )
  163. goto :eof
  164. :fd_half
  165. set "fd_half="
  166. set "one=%~1"
  167. set "one=%one:*.=%"
  168. for /l %%i in (0,1,32) do (
  169.     if "!one:~%%i,1!"=="" (set "one_i=!pre!0") else set "one_i=!pre!!one:~%%i,1!"
  170.     set /a one_ii=one_i,one_i=one_i/2,one_mod=one_ii%%2
  171.     if "!one_mod!"=="0" (set "pre=") else set /a pre=one_mod
  172.     set "fd_half=!fd_half!!one_i!"
  173.     if "!one:~%%i,1!"=="" (if "!one_mod!"=="0" goto :fd_half_next)
  174.     )
  175. :fd_half_next
  176. set "fd_half=0.%fd_half%"
  177. goto :eof
复制代码

TOP

这里有几个浮点数计算的代码,感兴趣的朋友们可以一起看看:
http://bbs.bathome.net/thread-3322-1-1.html
http://bbs.bathome.net/thread-3372-1-1.html
我帮忙写的代码不需要付钱。如果一定要给,请在微信群或QQ群发给大家吧。
【微信公众号、微信群、QQ群】http://bbs.bathome.net/thread-3473-1-1.html
【支持批处理之家,加入VIP会员!】http://bbs.bathome.net/thread-67716-1-1.html

TOP

返回列表