最近做項目中,使用到了計算文件大小的問題,但是在bat中使用set /a計算數值時只能限制在32位二進制數的大小,會提示:無效數字。數字精確度限為 32 位。
於是從網上查詢看看其他人是怎么解決的,以下這些內容是部分摘選網頁的部分有用的內容,后面會給出參考出處的,有需要的話自行查看原始網頁!
=============================================================================================================
大家都知道批處理能處理的數最大是2^31-1(2 147 483 647)到-2^31(-2 147 483 648)對吧~
還有就是批處理不能進行小數點運算對吧?
然后我有個疑問:
批處理怎樣實現大數/有小數點的數的加、減、乘、除啊?
翻了論壇的帖子,看到很多是把數分為幾個數個一組,過后才合並回去
可是,
我看不懂各位高手的代碼~
請問這怎樣實現啊?
能否給出代碼
以及清楚、不太深奧的解釋?
滿意的——加分!
比如這個http://www.bathome.net/viewthread.php?tid=3372
發一段自己寫的。。沒什么效率可言。。主要是體現個人思路。。
@echo off call :Add 314649645665.32188 694784.876998798 pause&exit/b :Add number1 number2 ||@by zj ::不支持負數 Setlocal EnableDelayedExpansion set "bjs=%~1"&set "js=%~2" set "bjs=%bjs:-=%"&set "js=%js:-=%" for %%i in (bjs js) do ( ((echo !%%i!)|findstr /ic:"."||set "%%i=!%%i!.0")>nul for /f "tokens=1,2 delims=." %%j in ("!%%i!") do set "z_%%i=%%j"&set "x_%%i=%%k" ) ::::設定兩數的整數和小數部分,整數的給z_XXX,小數的給x_XXX call :lp z_bjs z_js z_max for /l %%i in (1 1 %lg_z_max%) do set "z_bjs=0!z_bjs!"&set "z_js=0!z_js!" call :sub !z_bjs:~-%lg_z_max%!%x_bjs% !z_js:~-%lg_z_max%!%x_js% ::調用sub求出兩數各位數的和,大於10的進1,截取倒數第一位 goto :EOF :sub num1 num2 ||小數部分(左補零對齊) Setlocal set ".bjs=%~1"&set ".js=%~2" call :lp .bjs .js .max set/a lg_.max-=1 for /l %%i in (%lg_.max% -1 0) do ( set "x=!.bjs:~%%i,1!"&set "y=!.js:~%%i,1!" for %%j in (x y p) do (if not defined %%j set "%%j=0") set/a bit_sum=!x!+!y!+!p:~,1! set "bit_sum=0!bit_sum!"&set "p=!bit_sum:~-2,1!" set "sum=!bit_sum:~-1!!sum!" ) call :lp x_bjs x_js x_max set "sum=!sum:~,-%lg_x_max%!.!sum:~-%lg_x_max%!" if "%sum:~-2,2%" equ ".0" (echo %sum:~,-2%) else echo %sum% Endlocal&goto :EOF ::最左位則全部截取,這里的sub函數是關鍵 :LgStr set "n=0" :_LgStr set "str=%~1"&set/a n+=1 if not "!str:~%n%!"=="" goto :_LgStr goto :EOF :lp for %%i in (%~1 %~2) do (call :lgstr !%%i!&set "lg_%%i=!n!") if !lg_%~1! geq !lg_%~2! (set "lg_%~3=!lg_%~1!") else set "lg_%~3=!lg_%~2!" goto :EOF
我的思路是模擬筆算,跟分組計算其實也差不多。。把兩數的計算全部當成小數部分,前面補零,最后用截取來確定所得數的小數點位置。。大概就這樣吧。。純主觀,僅參考。。講的有點亂不知道樓主有沒有明白。。個人覺得大量使用CALL是個遺憾。。但只求完成任務。。
說實在的我我不太會表達,可能注釋了還是沒清楚,將就的看吧,或者不看也罷。
出處:http://bbs.bathome.net/viewthread.php?tid=13886
=======================================================================================
批處理函數:大數字加減乘除、時期時間計算、數字排序、進制轉換等
發幾個我的函數
2009-02-20 日更新:修正加法函數中一處bug,
增加整數除法“函數”(內勘多個標簽,應該不算標准的封裝)
2009-02-18 日更新:
更新乘法函數,大大縮短代碼,並且效率大大提升,且不再受位數限制。
理論上只要積不超過變量賦值的最大位數就可以。
更新加法函數:代碼略增,效率略為提高,且不再受位數限制。
更新減法函數:代碼略增,效率提高,位數由200提升到1000位。
一、加法函數 任意位數 的正整數 進行 加法計算
二、減法函數 可以對 200位 以內正整數 進行 減法計算
三、乘法函數 可以對 任意位數 的正整數進行 乘法計算
四、計算批處理運行時間函數 時間必須是24小時制,未考慮時間為00點的情況。
五、查詢指定天數前的日期(作者:Will Sort 出自:cn-dos )
六、數字排序函數
七、關於進制轉換的函數
1、任意進制互轉(只能處理cmd范圍內的數)
標簽段以封裝,可直接調用,使用方法見標簽上方的說明
為方便使用,標簽以外的代碼作了界面美化等處理。使得代碼略顯臃腫。。。
2、二進制轉十六進制(封裝)(通過4位一段轉換,可處理超大數)
3、十六進制轉二進制(封裝)(通過4位一段轉換,可處理超大數)
4、二進制轉十進制(封裝)(只能處理cmd范圍內的數,小巧方便代碼中調用)
5、獲取10進制數(含負數)的 原碼、反碼、補碼(未封裝)(只能處理cmd范圍內的值)
完全不懂計算機,只理解為計算機中負數用補碼表達
代碼中二進制數用32位顯示,超出32位的會出錯,
呵呵,不知道電腦中有沒有用32位以上表達的二進制數,哈哈外行話見笑了^_^
6、綜合以上對2、8、10、16進制數進行轉換、(未封裝)
顯示轉換后的2、8、10、16進制數及 原碼、反碼、補碼
@echo off call :jia 354687654165435 35486456 ok echo %ok% pause :jia 加法函數(封裝)by @隨風 @bbs.bathome.net ::計算任意位數的正整數加法 setlocal enabledelayedexpansion&set f=&set "t=" set var1=%~1&set var2=%~2&set /a j=0,n1=0,n2=0 for /l %%a in (0 1 9) do (set vard1=&set "vard2=" set var1=!var1:%%a= %%a !&set var2=!var2:%%a= %%a !) for %%a in (!var1!)do (set/a n1+=1&set vard1=%%a !vard1!) for %%a in (!var2!)do (set/a n2+=1&set vard2=%%a !vard2!) (if !n1! lss !n2! (set var1=%var2%&set "var2=%var1%" set vard1=%vard2%&set vard2=%vard1%))&set "var2=!var2: =!" for %%a in (!vard1!) do (if "!var2!"=="" set /a var2=0 set /a a=%%a+!var2:~-1!+j&set t=!a:~-1!!t!&set "a=0!a!" set "j=!a:~-2,1!"&set var2=!var2:~0,-1!) if !j! neq 0 set "t=!j!!t!" Endlocal&set %~3=%t%&goto :EOF -------------------------------------------------- @echo off call :jian 354687654165435 35486456 ok echo %ok% pause :jian 減法函數(封裝)by @隨風 @bbs.bathome.net ::計算1000位以內的正整數減法 setlocal enabledelayedexpansion&&set t=&set f=&set "lin=" for /l %%a in (1 1 10) do set "lin=0000000000!lin!" set lin=!lin!!lin!!lin!!lin!!lin!&set "lin=!lin!!lin!" set var1=!lin!%~1&set var2=!lin!%~2&set vard1=&set/a j=0 set var1=!var1:~-1000!&set "var2=!var2:~-1000!" if "!var1!" lss "!var2!" (set var1=%~2&set "var2=%~1" set "f=-") else set var1=%~1&set "var2=%~2" for /l %%a in (0 1 9) do set "var1=!var1:%%a= %%a !" for %%a in (!var1!) do set "vard1=%%a !vard1!" for %%a in (!vard1!) do (if "!var2!"=="" set/a var2=0 set /a a=%%a-j,b=!var2:~-1! if !a! lss !b! (set /a a+=10,j=1)else set /a j=0 set /a w=a-b&set t=!w!!t!&set var2=!var2:~0,-1!) for /f "tokens=* delims=0" %%a in ("!t!") do ( if "%%a"=="" (set t=0) else set "t=%%a") Endlocal&set %~3=%f%%t%&goto :EOF -------------------------------------------------- @echo off call :cen 354687654165435 35486456 ok echo %ok% pause :cen 乘法函數(封裝)by @隨風 @bbs.bathome.net ::計算任意位數的正整數乘法 setlocal enabledelayedexpansion if "%~1"=="0" Endlocal&set %~3=0&goto :EOF if "%~2"=="0" Endlocal&set %~3=0&goto :EOF set f=&set jia=&set ji=&set /a n1=0,n2=0 set vard1=&set "vard2="&set var1=%~1&set "var2=%~2" for /l %%a in (0 1 9) do ( set var1=!var1:%%a= %%a !&set var2=!var2:%%a= %%a !) for %%a in (!var1!)do (set /a n1+=1&set vard1=%%a !vard1!) for %%a in (!var2!)do (set /a n2+=1&set vard2=%%a !vard2!) if !n1! gtr !n2! (set vard1=%vard2%&set vard2=%vard1%) for %%a in (!vard1!) do (set "t="&set /a j=0 for %%b in (!vard2!) do (if "!jia!"=="" set /a jia=0 set /a a=%%a*%%b+j+!jia:~-1!&set "t=!a:~-1!!t!" set a=0!a!&set "j=!a:~-2,1!"&set jia=!jia:~0,-1!) set "ji=!t:~-1!!ji!" if "!j:~0,1!"=="0" (set ss=) else set "ss=!j:~0,1!" set jia=!ss!!t:~0,-1!) if not "!j:~0,1!"=="0" set "t=!j:~0,1!!t!" set "ji=!t!!ji:~1!" Endlocal&set %~3=%ji%&goto :EOF -------------------------------------------------- @echo off set suru=000012/001200 call :cu0 %suru:/= % ok echo. %ok% pause exit :cu0 500位內整數除法函數(封裝)by @隨風 bbs.bathome.net ::函數內有 cu1 cu2 cu3 cu4 四個標簽,引用時需注意 setlocal enabledelayedexpansion&set "lin=00000" set /a zongw=1000,cs1w=0,cs2w=0,falg=0,x=0 if "!str!"=="1" Endlocal&set %~3=%ff%!num!&goto :EOF if "%~1"=="0" set sang=0&goto cu4 if "!str!"=="0" set sang=以零為除數的錯誤。&goto cu4 if not defined xiaosu set /a xiaosu=10 for /l %%a in (1 1 5) do set "lin=!lin!!lin!!lin!" set sang=&set ppp=&set var1=%~1&set "var2=%~2" for /f "tokens=* delims=0" %%a in ("!var1!")do set var1=%%a for /f "tokens=* delims=0" %%a in ("!var2!")do set var2=%%a for /l %%a in (0 1 9)do (set "var1=!var1:%%a= %%a !" set "var2=!var2:%%a= %%a !") for %%a in (!var1!) do set /a cs1w+=1 for %%a in (!var2!) do set /a cs2w+=1 for /l %%a in (1 1 10) do (set t=&set cs=%~2&set/a j=0 for /l %%b in (1 1 !cs2w!) do (set /a a=%%a*!cs:~-1!+j set t=!a:~-1!!t!&set a=0!a!&set "j=!a:~-2,1!" set cs=!cs:~0,-1!&set cs%%a=&set "bj%%a=") if !j! neq 0 (set cs%%a=!lin!!j!!t!&set "bj%%a=!j!!t!" ) else set cs%%a=!lin!!t!&set "bj%%a=!t!" set "cs%%a=!cs%%a:~-%zongw%!") set var2=!lin!!var2: =!&set "var2=!var2:~-%zongw%!" set /a cswc=cs1w-cs2w&set "var1=!var1: =!" if !cswc! lss 0 (set cswc=!cswc:-=!&set/a flag=1 for /l %%a in (1 1 !cswc!)do ( if %%a leq 11 set sang=0!sang!&set /a x=cswc-1 set "var1=!var1!0") set "sang=!sang:~0,1!.!sang:~1!") set ppp=!var1:~0,%cs2w%!&set "var1=!var1:~%cs2w%!" if !flag! equ 1 (set /a bul=1) else set /a bul=0 goto cu2 :cu1 if not defined var1 (set "var1=0" if not defined ppp goto cu4 if !flag! equ 0 (set sang=!sang!.&set /a flag=1)) set/a bul=1&set ppp=!ppp!!var1:~0,1!&set "var1=!var1:~1!" :cu2 if !x! geq %xiaosu% goto cu4 set pvar1=!lin!!ppp!&set "pvar1=!pvar1:~-%zongw%!" if "!pvar1!" lss "!var2!" ( if !bul! equ 1 (set sang=!sang!0&set /a bul=0 if !flag! equ 1 set /a x+=1) if "!ppp:~0,1!"=="0" set "ppp=" goto cu1) if !flag! equ 1 set /a x+=1 set /a bul=0 ::計算商 for /l %%a in (1 1 10) do ( if "!cs%%a!" equ "!pvar1!" ( set "sang=!sang!%%a"&set "yu=!bj%%a!"&goto cu3) if "!cs%%a!" gtr "!pvar1!" (set /a s=%%a-1 set "sang=!sang!!s!"&set yu=!t!&goto cu3) set "t=!bj%%a!") :cu3 計算差 set cjs=!ppp!&set cj1=&set m=&set/a jjj=0 for /l %%a in (0 1 9) do set "cjs=!cjs:%%a= %%a !" for %%a in (!cjs!) do set "cj1=%%a !cj1!" for %%a in (!cj1!) do (if "!yu!"=="" set/a yu=0 set /a a=%%a-jjj,b=!yu:~-1! if !a! lss !b! (set /a a+=10,jjj=1)else set/a jjj=0 set /a w=a-b&set m=!w!!m!&set yu=!yu:~0,-1!) for /f "tokens=* delims=0" %%m in ("!m!") do ( if "%%m"=="" (set m=0) else set "m=%%m") if !m! equ 0 ( if "!var1:0=!"=="" set sang=!sang!!var1!&goto cu4 set ppp=&goto cu1) else set "ppp=!m!" goto cu2 :cu4 if "!sang:~0,1!"=="." set "sang=0!sang!" Endlocal&set %~3=%ff%%sang%&goto :EOF -------------------------------------------------- @echo off set t=%time% call :time0 "%t%" "%time%" ok echo %ok% pause :time0 計算時間差 (封裝) @echo off&setlocal&set /a n=0&rem code 隨風 @bbs.bathome.net for /f "tokens=1-8 delims=.: " %%a in ("%~1:%~2") do ( set /a n+=10%%a%%100*360000+10%%b%%100*6000+10%%c%%100*100+10%%d%%100 set /a n-=10%%e%%100*360000+10%%f%%100*6000+10%%g%%100*100+10%%h%%100) set /a s=n/360000,n=n%%360000,f=n/6000,n=n%%6000,m=n/100,n=n%%100 set "ok=%s% 小時 %f% 分鍾 %m% 秒 %n% 毫秒" endlocal&set %~3=%ok:-=%&goto :EOF -------------------------------------------------- 數字排序 @echo off :start setlocal enabledelayedexpansion&cls for /l %%a in (1 1 10) do set str=!str! !random! echo.&echo %str% call :sort "%str%" ok echo %ok% pause>nul endlocal&goto start :sort 可以處理0開頭的數、重復數及200位以內的超大整數(封裝) @echo off&setlocal enabledelayedexpansion for /f "delims==" %%a in ('set p. 2^>nul')do set "%%a=" for /l %%a in (1 1 20) do set "p.lin=0000000000!p.lin!" for %%a in (%~1) do (set s=!p.lin!%%a&set "s=!s:~-200!" if defined p...!s! (set p..%%a=!p..%%a! %%a set p...!s!=!p..%%a! %%a) else (set p...!s!=%%a)) for /f "tokens=2 delims==" %%a in ('set p...') do ( for %%i in (%%a) do set "p.ok=!p.ok! %%i") endlocal&set %~2=%p.ok:~1%&goto :EOF -------------------------------------------------- @echo off :start setlocal&cls set /p tian= 請指定要追溯的天數:&echo\ call :Date2Day "%date%" %tian% ok echo %ok% endlocal&pause>nul&goto start :Date2Day 計算指定天數 前/后 的日期及星期 (封裝) @echo off&setlocal ENABLEEXTENSIONS for /f "tokens=1-3 delims=/-:\, " %%a in ('echo/%~1') do ( set /a yy=%%a,mm=100%%b%%100,dd=100%%c%%100) set /a z=14-mm,z/=12,y=yy+4800-z,m=mm+12*z-3,j=153*m+2 set /a j=j/5+dd+y*365+y/4-y/100+y/400-2472633 set /a i=j-%~2,a=i+2472632,b=4*a+3,b/=146097,c=-b*146097,c/=4,c+=a set /a d=4*c+3,d/=1461,e=-1461*d,e/=4,e+=c,m=5*e+2,m/=153,dd=153*m+2,dd/=5 set /a dd=-dd+e+1,mm=-m/10,mm*=12,mm+=m+3,yy=b*100+d-4800+m/10 (if %mm% LSS 10 set mm=0%mm%)&(if %dd% LSS 10 set dd=0%dd%) for %%a in (一/1 二/2 三/3 四/4 五/5 六/6 日/0) do ( for /f "tokens=1,2 delims=/" %%i in ("%%a")do set %%i=%%j&set ".%%j=%%i") if %~2 gtr 0 (set /a d=^(7-%~2%%7+%date:~-1%^)%%7&set x=前) else ( set /a d=^(~%~2+1+%date:~-1%^)%%7&set x=后) call set "d=星期%%.%d%%%" endlocal&set %~3=%yy%-%mm%-%dd% %d%&goto :EOF -------------------------------------------------- 進制轉換(函數) 代碼1、任意進制互轉 @echo off&color 1f&set /a q=10,h=2 title 任意進制互轉 默認:%q%進制轉%h%進制 :start setlocal&echo.&echo. 被轉換的數 被轉換數的進制 需轉換成的進制 echo.&echo. 如:95 16 10 表示將 16進制數95 轉換 為10進制數 echo.&echo. 參數可用分割符為 空格 / + - \ 如:95/16/10 或95+16+10 echo.&echo. 默認將 10進制 轉換為 2進制(即上例中如果不輸入 16 10 則默認為 10 2) echo.&set /p num= 請輸入需轉換的數 &cls if not defined num endlocal&goto start for /f "tokens=1-3 delims=/+-\ " %%a in ("%num%") do ( set "num=%%a" if not "%%b"=="" if not "%%c"=="" set /a q=%%b,h=%%c ) call :nxn "%num%" ok %q% %h% for /l %%a in (1 1 12)do ( if %%a equ 4 ( echo. %q%進制轉%h%進制 結果 echo.&echo. %num% = %ok% )else echo\ ) set /a w=%random%%%2 if %w% equ 1 (set f=1f) else (set f=df) color %f%&endlocal&goto start ::函數使用方法:call :nxn "98" ok 10 2 ::call :nxn "被轉換的數" 保存結果的變量名 被轉換數的進制 需轉換成的進制 ::默認將 10進制 轉換為 2進制(即上例中不輸入 10 2) :nXn 任意進制互轉 @隨風 @bbs.bathome.net(封裝) @echo off&setlocal enabledelayedexpansion if "%~4"=="" (set /a q=10,h=2)else (set /a q=%~3,h=%~4) set "str=0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" for /l %%a in (0 1 35)do set .%%a=!str:~%%a,1!&set ".!str:~%%a,1!=%%a" set sun=&set jie=&set "var=%~1"&set /a nnn=1,num=0 for /l %%a in (0 1 100) do ( if not "!var:~%%a,1!"=="" (call set sun=%%.!var:~%%a,1!%% !sun!)) for %%a in (!sun!) do set /a num=%%a*nnn+num,nnn*=q :10進制轉n進制 set /a yu=num%%h,num/=h set "jie=!.%yu%!!jie!"&if !num! gtr 0 goto 10進制轉n進制 endlocal&set %~2=%jie%&goto :EOF -------------------------------------------------- 代碼2、二進制轉十六進制(封裝)(通過4位一段轉換,可處理超大數) @echo off&color 1f&title 二進制 轉 十六進制 call :2x16 "11111111 11111111 11111111 11111110" ok echo %ok% pause ::以4位一段,分別轉換為十六進制,不必考慮超大數問題 :2x16 二進制 轉 十六進制 @隨風 @bbs.bathome.net (封裝) @echo off&setlocal enabledelayedexpansion set "str=0123456789ABCDEF" set k=&set kk=&set xx=&set "x=000%~1" set x=!x:0= 0!&set x=!x:1= 1!&set /a jj=0,ss=1 for %%a in (!x!) do set "xx=%%a !xx!" for %%a in (!xx!) do (set /a jj+=%%a*ss,ss=ss*2 if !ss! equ 16 set k=!jj! !k!&set /a jj=0,ss=1) for %%a in (!k!) do set kk=!kk!!str:~%%a,1! endlocal&set %~2=%kk%&goto :EOF -------------------------------------------------- 代碼3、十六進制轉二進制(封裝)(通過4位一段轉換,可處理超大數) @echo off&color 1f&title 十六進制 轉 二進制 set mmm=bfa35e7d8 call :16x2 %mmm% ok echo.&echo 十六進制 %mmm% echo.&echo 二進制 %ok% echo.&pause ::以4位一段,分別轉換為二進制,不必考慮超大數問題 :16x2 十六進制 轉 二進制 @隨風 @bbs.bathome.net (封裝) @echo off&setlocal enabledelayedexpansion set str=0123456789abcdef&set ok=&set "num=%~1" for /l %%a in (0 1 15) do (set ".!str:~%%a,1!=%%a" call set "num=%%num:!str:~%%a,1!= !str:~%%a,1!%%") for %%i in (!num!) do (set /a x=0,n=!.%%i! for %%a in (8 4 2 1) do (set /a x+=%%a if !n! geq !x! (set ok=!ok!1) else ( set ok=!ok!0&set /a x-=%%a))) endlocal&set %~2=%ok%&goto :EOF -------------------------------------------------- 代碼4、二進制轉十進制(封裝)(只能處理cmd范圍內的數,小巧方便代碼中調用) @echo off call :2x10 01100100 ok echo %ok% pause :2x10 2進制轉 10進制 @隨風 @bbs.bathome.net (封裝) @echo off&setlocal enabledelayedexpansion set /a nnn=1,num=0&set nn=&set "n=%~1" set "n=!n:0= 0!"&set "n=!n:1= 1!" for %%a in (!n!) do set "nn=%%a !nn!" for %%a in (!nn!) do set /a num+=%%a*nnn,nnn*=2 endlocal&set %~2=%num%&goto :EOF -------------------------------------------------- 代碼5、獲取10進制數(含負數)的 原碼、反碼、補碼(未封裝) @echo off&color 1f&title 獲取10進制數的 原碼、反碼、補碼 ::獲取10進制數的 原碼、反碼、補碼 ::計算機中 負數用補碼表達 ::補碼:反碼+1 ::反碼:將二進制數(原碼)按位取反 (即:1變0、0變1) ::原碼:一個整數,按照絕對值大小轉換成的二進制數,稱為原碼。 ::個人理解為在計算機中表達負數的二進制數叫補碼 ::所以以下代碼中,若輸入的是負數則結果中補碼代表該數 @echo off&rem @隨風 @bbs.bathome.net @2009-01-15 :start setlocal enabledelayedexpansion for /l %%a in (1 1 15) do set "lin=00000!lin!" echo.&echo.&set /p y10= 請輸入一個10進制數可以為負數 &cls if !y10! lss 0 (set /a n="~y10"+1,c=1) else set /a n=y10,c=1 :10x2 將10進制轉成2進制 原碼 set /a y=n%%2,n/=2&set "j=!y!!j!"&if !n! gtr 0 goto 10x2 set j=!lin!!j!&set "j=!j:~-32!" set ss=!j:0= 0!&set "ss=!ss:1= 1!" :: 獲取反碼 for %%a in (%ss%) do set /a n="^!%%a"&set "f=!f!!n!" set f=!lin!!f!&set f=!f:~-32!&set "ss=!f!" :buma 獲取補碼 set /a m=!ss:~-1!+c if !m! gtr 1 (set c=1&set b=0!b!)else set c=0&set "b=!m!!b!" set "ss=!ss:~0,-1!" if defined ss goto buma echo. echo 10進制數 %y10%&echo. echo 原碼 %j:~-32,8% %j:~-24,8% %j:~-16,8% %j:~-8% echo 反碼 %f:~-32,8% %f:~-24,8% %f:~-16,8% %f:~-8% echo 補碼 %b:~-32,8% %b:~-24,8% %b:~-16,8% %b:~-8% endlocal&goto start -------------------------------------------------- 代碼6、轉換 2、8、10、16、進制數並顯示2進制 原碼、反碼、補碼(未封裝) @echo off ::轉換 2、8、10、16、進制數並顯示2進制 原碼、反碼、補碼 ::計算機中 負數用補碼表達 ::補碼:反碼+1 ::反碼:將二進制數(原碼)按位取反 (即:1變0、0變1) ::原碼:一個整數,按照絕對值大小轉換成的二進制數,稱為原碼。 ::個人理解為在計算機中表達負數的二進制數叫補碼 ::完全不懂計算機,只理解為計算機中負數用補碼表達 ::代碼中二進制數用32位顯示,超出32位的會出錯 ::只能處理cmd范圍內的數 @echo off&title 轉換 2、8、10、16、進制數並顯示2進制 原碼、反碼、補碼 ::@隨風 @bbs.bathome.net @2009-1-12 set "str=0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" set "color1=1f&set color2=df"&color 1f for /l %%a in (0 1 35) do ( call set ".%%a=%%str:~%%a,1%%" call set ".%%str:~%%a,1%%=%%a" ) :start setlocal enabledelayedexpansion&color %color1% echo. echo. ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ echo. ┃ ┃ echo. ┃輸入格式:需轉換的數+該數的進制(可用分割符 / \ + - 空格)┃ echo. ┃ ┃ echo. ┃默認輸入的為10進制數、也可以是2、8、16進制、但必須指明進制┃ echo. ┃ ┃ echo. ┃如:需轉換16進制 2afd 則輸入 2afd+16 10進制數則不需要指明┃ echo. ┃ ┃ echo. ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ echo.&set /p num= 請輸入需轉換的數 &cls if not defined num endlocal&goto start for /f "tokens=1,2 delims=/\+- " %%a in ("%num%") do ( set "n0=%%a" if "%%b"=="" (set jz=10) else set /a jz=%%b ) echo.&echo 被轉換的數為: !jz!進制數 !n0!&echo. if !jz! equ 16 (set /a n10=0x!n0!) else ( if !jz! equ 10 (set n10=!n0!) else ( if !jz! equ 8 (set /a n10=0!n0!) else ( set /a nnn=1,n10=0&call :2x10 !n0! ))) for %%a in (16 10 8 2) do call :10進制轉n進制 !n10! %%a echo.&call :yuan&echo. endlocal&set color1=%color2%&set "color2=%color1%" goto start :10進制轉n進制 set /a yu=n10%%%~2,n10/=%~2 set "jie=!.%yu%!!jie!"&if !n10! gtr 0 goto 10進制轉n進制 set "xs= %~2" echo !xs:~-5! 進制 !jie! set d2=!jie!&set jie=&set "n10=%~1" goto :EOF :2x10 2進制轉10進制 set /a n10+=!n0:~-1!*nnn,nnn*=2 set "n0=!n0:~0,-1!" if defined n0 goto 2x10 goto :EOF :yuan for /l %%a in (1 1 15) do set lin=00000!lin! set j=!lin!!d2!&set "j=!j:~-32!" set ss=!j:0= 0!&set "ss=!ss:1= 1!" :: 獲取反碼 for %%a in (%ss%) do set /a n="^!%%a"&set "f=!f!!n!" set f=!lin!!f!&set f=!f:~-32!&set "ss=!f!" set /a c=1 :buma 獲取補碼 set /a m=!ss:~-1!+c if !m! gtr 1 (set c=1&set b=0!b!)else set c=0&set "b=!m!!b!" set "ss=!ss:~0,-1!" if defined ss goto buma echo 原碼 %j:~-32,8% %j:~-24,8% %j:~-16,8% %j:~-8% echo 反碼 %f:~-32,8% %f:~-24,8% %f:~-16,8% %f:~-8% echo 補碼 %b:~-32,8% %b:~-24,8% %b:~-16,8% %b:~-8% goto :EOF --------------------------------------------------
我貼一個較高效的浮點加法函數
@echo off set aa=%time% for /l %%a in (1,1,1000) do call :_ADD 123456722222222222222890.3212222222222222222222222 1222222222222222222.789233333333333333333333333 set/p =計算1000次,用時:<NUL&CALL goto :eof ::前面為演示用 ::::::::::::::::::::::::::::::::::::: ::浮點加法 call _ADD <被加數> <加數> [返回變量] :_ADD [var] //made by netbenton on 2009.10.09 :: ::分別支持十進制的64位整數和小數,一次計算僅用0.01秒 ::::::::::::::::::::::::::::::::::::: (setlocal enabledelayedexpansion set L=&for /l %%a in (1,1,8) do set L=!L!00000000 for /f "tokens=1-3 delims=." %%a in ("!L!%1.!L!") do set at=%%a&set aw=%%b%%c for /f "tokens=1-3 delims=." %%a in ("!L!%2.!L!") do set bt=%%a&set bw=%%b%%c set a=!at:~-64!!aw:~,64! set b=!bt:~-64!!bw:~,64! set e= set v=200000000 for /l %%a in (8,8,128)do set/a v=1!b:~-%%a,8!+1!a:~-%%a,8!+!v:~-9,-8!-2&set e=!v:~-8!!e! set e=!e:0= ! for /f "tokens=*" %%a in ("!e:~,-64!.!e:~64!") do set e=%%~nxa for %%a in ("!e: =0!") do endlocal&(if %3.==. (echo %%~a) else set %3=%%~a) exit/b) ::計算時差函數 :etime [return] // By plp626 On 09-7-20 setlocal enabledelayedexpansion&set be=%~1;%~2&set be=!be::=;1!&set n= for %%a in (%be:.=%)do set/a n+=1&set t!n!=%%a set/a n=((t4-t1)*60+t5-t2)*6000+t6-t3,s=n/100,w=n%%100/10,f=n%%100%%10 endlocal&(if %3.==. (echo %s%.%w%%f%) else set %3=%n:-=%)&exit/b
rem 這里分別獲取加數和被加數,小數點前和后各64個字符
set a=!at:~-64!!aw:~,64!&set b=!bt:~-64!!bw:~,64!
rem 這里其實是使用了for語句的變量擴展:去雙引號后去文件名和擴展名
for /f "tokens=*" %%a in ("!e:~,-64!.!e:~64!") do set e=%%~nxa
我也寫了個批處理大數浮點乘法,任意位,任意小數乘法均可以計算。
全精度浮點乘,批處理的各種特殊性全部考慮,計算效率極佳。
只受限於批處理的輸入,批處理最多允許輸入一千多位。但是,程序可以擴展。稍加改造即可用多個字符串來存儲輸入。這樣理論上是無限制的。當然最大限制是6300位大數,源於批處理的2的31次方限制。
@echo off&mode con cols=58 lines=38 :MAIN cls echo 浮點乘表達式^(乘號用*表示^) set /p Express=-^> setlocal enabledelayedexpansion REM 浮點計數 for /f "tokens=1,2 delims=*" %%a in ("!Express!") do ( set A=%%a&set A=!A: =! set B=%%b&set B=!B: =! ) for /f "tokens=1,2 delims=." %%a in ("!A!") do ( set A1=%%a&set A=!A1!%%b if "%%b"=="" (set PA=0) else ( set A2=%%b for %%i in (512 256 128 64 32 16 8 4 2 1) do ( if not "!A2:~%%i!"=="" ( set/a PA+=%%i set "A2=!A2:~%%i!" ) ) if "!A2:~1!"=="" (set/a PA+=1) ) ) for /f "tokens=1,2 delims=." %%a in ("!B!") do ( set B1=%%a&set B=!B1!%%b if "%%b"=="" (set PB=0) else ( set B2=%%b for %%i in (512 256 128 64 32 16 8 4 2 1) do ( if not "!B2:~%%i!"=="" ( set/a PB+=%%i set "B2=!B2:~%%i!" ) ) if "!B2:~1!"=="" (set/a PB+=1) ) ) set/a PO=PA+PB REM 位數信息 CALL :CUT !A! A NA CALL :CUT !B! B NB set/a N=NA+NB,NA*=3,NB*=3 echo ====================================== echo 被乘數信息: 有效!NA!位,浮點!PA!位 echo 乘數信息: 有效!NB!位,浮點!PB!位 echo ====================================== set t1=!time:~-5! REM 核心乘法 for /l %%i in (1 1 !N!) do ( for /l %%j in (1 1 %%i) do ( set/a j=%%i-%%j+1 if defined A[%%j] ( if defined B[!j!] ( set/a sum=A[%%j]*B[!j!]+sum ) ) ) set/a s=sum+1000 set sum=!sum:~0,-3! set pul=!s:~-3!!pul! ) :DIS 顯示結果 if !PO! equ 0 ( for /l %%i in (1 1 5) do ( if "!pul:~0,1!"=="0" ( set pul=!pul:~1! ) ) echo =!pul! ) else ( set pre=!pul:~0,-%PO%! for /l %%i in (1 1 5) do ( if "!pre:~0,1!"=="0" ( set pre=!pre:~1! ) ) if not defined pre (set pre=0) echo =!pre!.!pul:~-%PO%! ) REM 毫秒計時器 set "t2=!time:~-5!" &set/a "t=1!t2:.=!-1!t1:.=!" &if !t! lss 0 (set/a t+=6000) set/p=耗時!t:~0,-2!秒!t:~-2!0毫秒 endlocal&goto MAIN :CUT 分割數組 set num=%1 if "!num:~-3!"=="!num:~-4!" ( set %2[1]=!num! set %3=1 goto :eof ) for /l %%i in (1 1 365) do ( if "!num:~0,-3!"=="" ( set/a %2[%%i]=!num! set %3=%%i goto :eof ) set/a %2[%%i]=1!num:~-3!-1000 set num=!num:~0,-3%! )
測試 615位大數 35486456354... 乘以 312位大數 35867...用時9秒。for循環的效率以及批處理脆弱的計算能力,導致它遠遠不及C語言(需要0.3秒).
---------------------------------------------------------------------------------------
下面是大整數加法,1000位加1000位范圍內,再多,cmd窗口輸不進去。效率基本0.0幾秒吧。
@echo off&setlocal enabledelayedexpansion title By Happy mode con cols=65 lines=35 REM 大數長度 set "MAX=1000" ^位 REM 分割大小 set "K=8" ^位 set /a CYC=MAX/K :MAIN cls echo 請輸入^(被加數^) set /p A=-^>: echo 請輸入^(加數^) set /p B=-^>: REM 優化字符 setlocal CALL :POINT !A! A N1 CALL :POINT !B! B N2 set /a B1=N1*K set /a B2=N2*K echo ====================================== echo 被加數信息: 預估!B1!位 echo 加數信息: 預估!B2!位 echo ====================================== echo 計算結果 REM 加法核心 if !N1! gtr !N2! (set RM=!N1! &set dx=B) else (set RM=!N2! &set dx=A) for /l %%i in (1 1 !RM!) do ( if not defined !dx![%%i] (set "!dx![%%i]=00000000") set /a sum=1!A[%%i]!+1!B[%%i]!+sum set S=!sum:~-%K%!!S! set /a sum=!sum:~0,1!-2 ) REM 顯示 :DISP for /l %%i in (1 1 8) do (if "!S:~0,1!"=="0" (set S=!S:~1!)) if "!S!"=="" (set S=0) echo,!S! pause>nul endlocal goto MAIN REM 分割數位 :POINT set num=%1 for /l %%i in (1 1 !CYC!) do ( set %2[%%i]=!num:~-%K%! set num=!num:~0,-%K%! if "!num!"=="" ( set /a CU=!%2[%%i]!+100000000 set %2[%%i]=!CU:~-%K%! set /a %3=%%i goto :eof ) )
批處理,兩個不分正負的大數的加減運算
@echo off for %%a in ( "1.1 - 0.9" "1.12345678987654321 + -9.87654321012345679" "6.6543212345678 - 5.5432101234567" "-2 - 2.4948463537" "-93701350643248383.03974234214254643221455737 - 364354503.67365700005267589864236576" "-0.4253500 - -5762.4948463537" "0 - 0" "232.556 - 232.556" "0 + 0" "0 - 234.342250988" "-3.4536 - 3456" "325689088000004600 - 94872734352.487409900094848377236474830937" "-34.435464573575735 + -3425.0298576283039836" "4 - 1000000.0000001" ) do ( for /f "tokens=1-3" %%i in (%%a) do ( setlocal enabledelayedexpansion rem 由於cmd自身的各種限制,不做過多考慮,暫支持兩個長度在4000位以內不分正負的整數或小數的加減運算 rem 用法call :calc num1 [+/-] num2 result call :calc %%i %%j %%k result echo;%%~a echo;= !result! echo; endlocal ) ) pause&exit :calc rem 屏蔽數字合法性檢測可提高效率 echo;%~1|findstr "^-0\.0*[1-9][0-9]*$ ^0\.0*[1-9][0-9]*$ ^0$ ^-[1-9][0-9]*$ ^[1-9][0-9]*$ ^-[1-9][0-9]*\.[0-9][0-9]*$ ^[1-9][0-9]*\.[0-9][0-9]*$">nul||set n=1 echo;%~3|findstr "^-0\.0*[1-9][0-9]*$ ^0\.0*[1-9][0-9]*$ ^0$ ^-[1-9][0-9]*$ ^[1-9][0-9]*$ ^-[1-9][0-9]*\.[0-9][0-9]*$ ^[1-9][0-9]*\.[0-9][0-9]*$">nul||set n=1 if defined n (set "%~4=數字不合法"&goto :eof) if "%~2" neq "+" if "%~2" neq "-" (set "%~4=算術運算符不正確"&goto :eof) if "%~4" equ "" (set "%~4=缺少結果變量"&goto :eof) if "%~1" equ "0" ( if "%~3" equ "0" (set "%~4=0") else ( set a=%~3 if "%~2" equ "+" ( set "%~4=%~3" ) else ( if "!a:~,1!" equ "-" (set "%~4=!a:~1!") else (set "%~4=-%~3") ) ) goto :eof ) if "%~3" equ "0" (set "%~4=%~1"&goto :eof) if "%~1" equ "%~3" if "%~2" equ "-" (set "%~4=0"&goto :eof) set a=%~1.0 set b=%~3.0 for /f "tokens=1,2 delims=." %%a in ("%a:-=%") do set "a_1=%%a"&set "a_2=%%b" for /f "tokens=1,2 delims=." %%a in ("%b:-=%") do set "b_1=%%a"&set "b_2=%%b" call :strlen %a_1% L1_1 call :strlen %a_2% L1_2 call :strlen %b_1% L2_1 call :strlen %b_2% L2_2 for %%i in (1 2) do ( set "zero="&set m=0 if !L1_%%i! leq !L2_%%i! ( set /a m=L2_%%i-L1_%%i if !m! neq 0 ( for /l %%a in (1 1 !m!) do set zero=!zero!0 ) if "%%i" equ "1" (set a_%%i=!zero!!a_%%i!) else set a_%%i=!a_%%i!!zero! set Len_%%i=!L2_%%i! ) else ( set /a m=L1_%%i-L2_%%i for /l %%a in (1 1 !m!) do set zero=!zero!0 if "%%i" equ "1" (set b_%%i=!zero!!b_%%i!) else set b_%%i=!b_%%i!!zero! set Len_%%i=!L1_%%i! ) ) set /a Len=Len_1+Len_2+1 if "%~2" equ "+" ( if "!a:~,1!" neq "-" ( if "!b:~,1!" neq "-" ( call :jia %a_1%.%a_2% %b_1%.%b_2% %Len% s set "%~4=!s!" ) else ( call :jian %a_1%.%a_2% %b_1%.%b_2% %Len% s if "%a_1%.%a_2%" gtr "%b_1%.%b_2%" (set "%~4=!s!") else set "%~4=-!s!" ) ) else ( if "!b:~,1!" neq "-" ( call :jian %a_1%.%a_2% %b_1%.%b_2% %Len% s if "%a_1%.%a_2%" gtr "%b_1%.%b_2%" (set "%~4=-!s!") else set "%~4=!s!" ) else ( call :jia %a_1%.%a_2% %b_1%.%b_2% %Len% s set "%~4=-!s!" ) ) ) else ( if "!a:~,1!" neq "-" ( if "!b:~,1!" neq "-" ( call :jian %a_1%.%a_2% %b_1%.%b_2% %Len% s if "%a_1%.%a_2%" lss "%b_1%.%b_2%" (set "%~4=-!s!") else set "%~4=!s!" ) else ( call :jia %a_1%.%a_2% %b_1%.%b_2% %Len% s set "%~4=!s!" ) ) else ( if "!b:~,1!" neq "-" ( call :jia %a_1%.%a_2% %b_1%.%b_2% %Len% s set "%~4=-!s!" ) else ( call :jian %a_1%.%a_2% %b_1%.%b_2% %Len% s if "%a_1%.%a_2%" lss "%b_1%.%b_2%" (set "%~4=!s!") else set "%~4=-!s!" ) ) ) goto :eof :strlen setlocal set "$=%1#" set len=&for %%a in (4000 2048 1024 512 256 128 64 32 16)do if !$:~%%a!. neq . set/a len+=%%a&set $=!$:~%%a! set $=!$!fedcba9876543210&set/a len+=0x!$:~16,1! endlocal&set %2=%len%&goto :eof :jia setlocal set a=%~1 set b=%~2 set t=0 set "s=" for /l %%a in (-1 -1 -%~3) do ( if "!a:~%%a,1!" equ "." ( set s=.!s! ) else ( set /a "c=t+!a:~%%a,1!+!b:~%%a,1!" if !c! geq 10 (set t=1) else set t=0 set s=!c:~-1!!s! ) ) if %t% equ 1 (set s=1!s!) for /f "tokens=1,2 delims=." %%a in ("%s%") do ( for /f "tokens=1* delims=0" %%c in (".%%b") do if "%%c%%d" equ "." set s=%%a ) endlocal&set %~4=%s%&goto :eof :jian setlocal if "%~1" lss "%~2" ( set a=%~2 set b=%~1 ) else ( set a=%~1 set b=%~2 ) set t=0 set "s=" for /l %%a in (-1 -1 -%~3) do ( if "!a:~%%a,1!" equ "." ( set s=.!s! ) else ( set /a "c=10+!a:~%%a,1!-!b:~%%a,1!-t" if !c! lss 10 (set t=1) else set t=0 set s=!c:~-1!!s! ) ) for /f "tokens=1,2 delims=." %%a in ("%s%") do ( for /f "tokens=* delims=0" %%c in ("%%a") do if "%%c" equ "" (set pre=0) else set pre=%%c for /f "tokens=* delims=0" %%c in ("%%b") do if "%%c" equ "" (set s=!pre!) else set s=!pre!.%%b ) endlocal&set %~4=%s%&goto :eof
出處:http://www.bathome.net/viewthread.php?tid=3372
========================================================================
個人總結
參考上面的 _ADD 方法,上面的有個bug,如計算10+20,則為3
稍微修改了bug,以及部分語句的合並,如下
::參考浮點加法 call _ADD <被加數> <加數> [返回變量] ::分別支持十進制的64位整數部分和64位小數部分,一次計算僅用0.01秒 :bigNumAdd <被加數> <加數> [返回變量] // by jack on 2021-09-03 (setlocal enabledelayedexpansion set L=&for /l %%a in (1,1,8) do set L=!L!00000000 for /f "tokens=1-3 delims=." %%a in ("!L!%1.!L!") do set at=%%a&set aw=%%b%%c for /f "tokens=1-3 delims=." %%a in ("!L!%2.!L!") do set bt=%%a&set bw=%%b%%c set a=!at:~-64!!aw:~,64!&set b=!bt:~-64!!bw:~,64!&set e=&set v=200000000 for /l %%a in (8,8,128)do set/a v=1!b:~-%%a,8!+1!a:~-%%a,8!+!v:~-9,-8!-2&set e=!v:~-8!!e! set e=!e:0= !&for /f "tokens=*" %%a in ("!e:~,-64!_.!e:~64!") do set e=%%~nxa set e=!e:_=!&for %%a in ("!e: =0!") do endlocal&(if %3.==. (echo %%~a) else set %3=%%~a) exit/b)
rem 這里分別獲取加數和被加數,小數點前和后各64個字符
set a=!at:~-64!!aw:~,64!&set b=!bt:~-64!!bw:~,64!
::這里其實是使用了for語句的變量擴展:去雙引號后去文件名和擴展名,同時這里也是10+20=3的bug的問題所在
for /f "tokens=*" %%a in ("!e:~,-64!.!e:~64!") do set e=%%~nxa