Board logo

标题: [数值计算] [原创]批处理函数:自然数加法 整数加减法 自然数带余数除法 正整数阶乘分解 [打印本页]

作者: hongrk    时间: 2019-4-5 21:34     标题: [原创]批处理函数:自然数加法 整数加减法 自然数带余数除法 正整数阶乘分解

本帖最后由 hongrk 于 2019-5-3 14:32 编辑

1.加法函数
①自然数范围(但会受限于call所能够传递的位数),效率较高(4416位+2496位平均用时94ms),支持开头含0与加数未定义情况。
②整数加减法合一,效率相对上一个微低(2496位-4416位平均用时115ms, 4416位+2496位平均用时100ms),支持开头含0(包括第一位为负号然后一串0)与未定义情况
2.除法函数 限制较大,只能做到 自然数除以一个8位数以内的自然数,得到商与余数。
2019.5.3 修了一个BUG
3.阶乘分解 随手写,没啥用。而且没封装

自然数加法函数:
①长数版,效率不如短数版,尤其两数位数差距大时远远远不如,但更小巧。(目前还没找到一个比短数版快的例子……建议用短数版。这个嘛……作对照好了)
  1. @echo off&setlocal enabledelayedexpansion
  2. set a=456456521000210000000000000000874112115674511111111111111110019999999
  3. set b=923451344221111111111111111000000000001
  4. for /l %%a in (1,1,6)do set a=!a!!a!
  5. for /l %%b in (1,1,6)do set b=!b!!b!
  6. set t1=%time%
  7. call :add "%a%" "%b%" "P"
  8. ::【引号可有可无;但当加数可能未定义,或结果变量名里含有空格时,必须有】
  9. call :tt %t1% %time% t
  10. echo %t%
  11. echo %P%&pause&exit
  12. :add
  13. setlocal enabledelayedexpansion&set c1=%~1&set c2=%~2&set c=0&set s=
  14. ::c1、c2为加数,c为进位标识符,s储存结果。
  15. for %%i in (1 2)do set "$=!c%%i!#"&set N%%i=0&for %%j in (4608 2304 1152 576 288 144 72 36 18 9)do if !$:~%%j!. NEQ . set/aN%%i+=%%j&set $=!$:~%%j!
  16. ::数出c1、c2的位数,去成9的倍数,即节数*9
  17. if %N1% GEQ %N2% (set N=21%N1%) else set N=12%N2%
  18. ::取其大者存在N,N的第一位用于标识短数,第二位用于标识长数
  19. for /l %%i in (9 9 %N:~2%)do set c%N:~,1%=000000000!c%N:~,1%!&set/ac=(t=1!c1:~-9!-2000000000+1!c2:~-9!+c)/1000000000&set c%N:~,1%=!c%N:~,1%:~9,-9!&set c%N:~1,1%=!c%N:~1,1%:~,-9!&set t=00000000!t!&set s=!t:~-9!!s!
  20. ::一直算到长数只剩0-8位。此过程中长数永远能截到9位不须补0,省掉一个大set,而短数就要。因此切短数要去掉开头补的9个0,切长数就不能去。
  21. ::“长数”未定义时,则短数位数必在0-8之间,不会进此循环故不会出问题,因为下一行两数都前补9个0,未定义会被变成0.“短数”未定义时,可能会进此循环,但此循环中短数前补了9个0.
  22. set c1=000000000%c1%&set c2=000000000%c2%&set/ac=(t=1!c1:~-9!-2000000000+1!c2:~-9!+c)/1000000000&set s=!t!!s!&if !s! NEQ 0 for /f "tokens=* delims=0" %%i in ("!s!") do set "s=%%i"
  23. ::算掉长数的最后一节,如果结果开头有0则去掉。
  24. endlocal&set %~3=%s%&goto :eof
  25. :tt
  26. setlocal&set be=%1:%2
  27. for /f "delims=: tokens=1-6" %%a in ("%be:.=%")do set/at=(%%d-%%a)*360000+(1%%e-1%%b)*6000+1%%f-1%%c,t+=-8640000*("t>>31")
  28. endlocal&set %3=%t%0ms&exit/b
复制代码
②短数版,用时主要取决于短数节数。  因为注释太多了所以特地分开。
效率(for计算10/100/1000次取均值)(后跟长数版比较):
4416位+2496位 94.5ms  (270ms)
2496位+2496为 78ms   (130ms)
4416位+1位      4.9ms    (96ms) (这个极端例子差距比较明显)
552位+624位    11.9ms    (18ms)
63位+1位         2.7ms     (3.8ms)
9位+9位           2.68ms   (2.70ms)
  1. @echo off&setlocal enabledelayedexpansion
  2. set a=456456521000210000000000000000874112115674511111111111111110019999999
  3. set b=923451344221111111111111111000000000001
  4. for /l %%a in (1,1,6)do set a=!a!!a!
  5. for /l %%b in (1,1,6)do set b=!b!!b!
  6. set t1=%time%
  7. call :add "%a%" "%b%" "P"
  8. ::【引号可有可无;但当加数可能未定义,或结果变量名里含有空格时,必须有】
  9. ::【去开头0与防未定义的都揉进去了,反正基本不影响速度】
  10. call :tt %t1% %time% t
  11. echo %t%
  12. echo %P%&pause&exit
  13. ::【有2个标签:add与:sad.若不会出现两加数的位数差超过488+8=496位的,可把"call :sad %D:9= %"一处改为"for %%i in (%D:9= %)do set E=%%~ni"并把:sad标签删除,这同时还能微微加速。】
  14. :add
  15. if %1=="" (
  16. if %2=="" (set %~3=0)else set %~3=%~2
  17. exit/b)else if %2=="" set %~3=%~1&exit/b
  18. setlocal enabledelayedexpansion&set c1=%~1&set c2=%~2&set/ac=uh=0&set s=
  19. for %%i in (1 2)do (for /f "tokens=* delims=0" %%j in ("!c%%i!") do set "c%%i=%%j")&set "$=!c%%i!#"&set N%%i=0&for %%j in (4608 2304 1152 576 288 144 72 36 18 9)do if !$:~%%j!. NEQ . set/aN%%i+=%%j&set $=!$:~%%j!
  20. if %N1% LEQ %N2% (set/aM=9+N1,N=2%N1%) else set/aM=9+N2,N=1%N2%
  21. (if %N:~1% NEQ 0 set uh=,-%N:~1%)&for /l %%i in (9 9 %N:~1%)do set/ac=(t=1!c1:~-%%i,9!-2000000000+1!c2:~-%%i,9!+c)/1000000000&set t=00000000!t!&set s=!t:~-9!!s!
  22. set D=0!c%N:~,1%:~,-%M%!&set c1=000000000!c1:~%uh%!&set c2=000000000!c2:~%uh%!&set/ac=(t=1!c1:~-9!-2000000000+1!c2:~-9!+c)/1000000000&(if %N1% NEQ %N2% set t=00000000!t!)&if !t!. NEQ 0. set s=!t:~-9!!s!
  23. if %c%==0 endlocal&set %~3=%D:~1%%s%&exit/b
  24. call :sad %D:9= %&set E=!E: =9!&set/ap=!E:~-1!+1
  25. set q=!D:%E%=!&if defined q set q=!q:9=0!
  26. endlocal&set %~3=%E:~1,-1%%p%%q%%s%&exit/b
  27. :sad
  28. set E=%*&exit/b
  29. :tt
  30. setlocal&set be=%1:%2
  31. for /f "delims=: tokens=1-6" %%a in ("%be:.=%")do set/at=(%%d-%%a)*360000+(1%%e-1%%b)*6000+1%%f-1%%c,t+=-8640000*("t>>31")
  32. endlocal&set %3=%t%0ms&exit/b
复制代码
③短数版注释版
  1. @echo off&setlocal enabledelayedexpansion
  2. set a=456456521000210000000000000000874112115674511111111111111110019999999
  3. set b=923451344221111111111111111000000000001
  4. for /l %%a in (1,1,6)do set a=!a!!a!
  5. for /l %%b in (1,1,6)do set b=!b!!b!
  6. set t1=%time%
  7. call :add "%a%" "%b%" "P"
  8. ::【引号可有可无;但当加数可能未定义,或结果变量名里含有空格时,必须有】
  9. ::【去开头0与防未定义的都揉进去了,反正基本不影响速度】
  10. call :tt %t1% %time% t
  11. echo %t%
  12. echo %P%&pause&exit
  13. ::【有2个标签:add与:sad.若不会出现两加数的位数差超过488+8=496位的,可把"call :sad %D:9= %"一处改为"for %%i in (%D:9= %)do set E=%%~ni"并把:sad标签删除,这同时还能微微加速。】
  14. :add
  15. if %1=="" (
  16. if %2=="" (set %~3=0)else set %~3=%~2
  17. exit/b)else if %2=="" set %~3=%~1&exit/b
  18. ::防加数未定义。没事找事写成3行是怕“输入行过长”
  19. setlocal enabledelayedexpansion&set c1=%~1&set c2=%~2&set/ac=uh=0&set s=
  20. ::c1、c2为加数,c为进位标识符,s储存结果。uh是为了破莫名其妙的":~,-0什么都不取"
  21. for %%i in (1 2)do (for /f "tokens=* delims=0" %%j in ("!c%%i!") do set "c%%i=%%j")&set "$=!c%%i!#"&set N%%i=0&for %%j in (4608 2304 1152 576 288 144 72 36 18 9)do if !$:~%%j!. NEQ . set/aN%%i+=%%j&set $=!$:~%%j!
  22. ::前面的for /f作用是去掉开头的0.然后数出c1、c2的长度(去成9的倍数),分别存在N1、N2。c1或c2未定义时对应值给出0.
  23. if %N1% LEQ %N2% (set/aM=9+N1,N=2%N1%) else set/aM=9+N2,N=1%N2%
  24. ::把较小的“伪长度值”,其实就是完整节的数目*9,存到变量N。N前面标记好哪个是长数。M就1个用处:后面用来截D
  25. (if %N:~1% NEQ 0 set uh=,-%N:~1%)&for /l %%i in (9 9 %N:~1%)do set/ac=(t=1!c1:~-%%i,9!-2000000000+1!c2:~-%%i,9!+c)/1000000000&set t=00000000!t!&set s=!t:~-9!!s!
  26. ::前补1再减是为了除0,免得被当成八进制。此for循环计算结束后,短数尚未参与计算的位数为0-8.长数不确定。全过程可以保证9位相加,从而减少循环中执行的代码量。
  27. set D=0!c%N:~,1%:~,-%M%!&set c1=000000000!c1:~%uh%!&set c2=000000000!c2:~%uh%!&set/ac=(t=1!c1:~-9!-2000000000+1!c2:~-9!+c)/1000000000&(if %N1% NEQ %N2% set t=00000000!t!)&if !t!. NEQ 0. set s=!t:~-9!!s!
  28. ::set D前面添0是为了防止未定义问题。这里要取的是长数经2行运算后剩下的部分,也可能根本没有。
  29. ::再经一次运算后,短数必结束。因为此行中不能保证9位相加,所以需执行的代码变多。
  30. ::if !t!. NEQ 0.中的点,是为了防止Bat把它们当数算(不然000000000=0了)。之所以来这一个检测,是为了防2个数正好都算完了(即节数相同,这是最常见的情况了)的情况,同时也把c处理掉了方便下一行迅速结束。
  31. ::有的服Bat的设定,%c2:~,-0%直接什么都不取了。难道不应该是取"总长度-0"位,取全部吗? 变量uh破此坑。
  32. if %c%==0 endlocal&set %~3=%D:~1%%s%&exit/b
  33. ::c=0,下面不用进位了,于是直接把剩下的长数部分堆上去就好。去1位是因为D开头有个补的0
  34. ::以下操作的耗时稳定在10ms以下。但仍颇感可惜。需要执行下面的,正常需求下貌似不会很多。比如本例。
  35. call :sad %D:9= %&set E=!E: =9!&set/ap=!E:~-1!+1
  36. ::call的目的是去末尾空格,联合后一句即为去末尾的9.
  37. ::本想用set E=%%~ni来去末空格,但这样最多只能处理488位字符串,超过会出错。其他能用的就只有call法了,无奈之举
  38. ::效率差距:call法100次慢约100ms(此数值基本不随运算数长度变化),即1次会慢上1ms.在接受范围内。
  39. ::for循环没有while和do until真是严重差评,中间插goto还不肯马上跳出。不然用循环也是不错的选择
  40. ::D自第二位起全为9时,因为第一位固定了0,set/a一步可以把p算成1
  41. set q=!D:%E%=!&if defined q set q=!q:9=0!
  42. ::set q是把一串被切掉的原本在末尾的9弄出来变成0.本可以更简单,但未定义时字符串替换的乱搞实在是很气人
  43. endlocal&set %~3=%E:~1,-1%%p%%q%%s%&exit/b
  44. :sad
  45. set E=%*&exit/b
  46. :tt
  47. setlocal&set be=%1:%2
  48. for /f "delims=: tokens=1-6" %%a in ("%be:.=%")do set/at=(%%d-%%a)*360000+(1%%e-1%%b)*6000+1%%f-1%%c,t+=-8640000*("t>>31")
  49. endlocal&set %3=%t%0ms&exit/b
复制代码
③整数加减法合一函数
  1. @echo off&setlocal enabledelayedexpansion
  2. set a=456456521000210000000000000000874112115674511111111111111110019999999
  3. set b=923451344221111111111111111000000000001
  4. for /l %%a in (1,1,6)do set a=!a!!a!
  5. for /l %%b in (1,1,6)do set b=!b!!b!
  6. set t1=%time%
  7. call :add "-%a%" "%b%" "P"
  8. ::【%a%、%b%也可以是负数,call时再在前面添-则是减去负数,可以正常处理。】
  9. ::【引号可有可无;但当加数可能未定义,或结果变量名里含有空格时,必须有】
  10. call :tt %t1% %time% t
  11. echo %t%
  12. echo %P%&pause&exit/b
  13. ::【有2个标签:add与:sad.若不会出现两加数的位数差超过488+8=496位的,可把"call :sad !D:%u%= !"一处改为"for %%i in (!D:%u%= !)do set E=%%~ni"并把:sad标签删除,这同时还能微微加速。】
  14. :add
  15. setlocal enabledelayedexpansion&set c1=%~1&set c2=%~2&set/ac=v=0,k=-2000000000,u=9&for %%i in (s f j uh)do set %%i=
  16. ::啧,壮观的设置。c1、c2为加数,c为进/退位标识符,v、u、k在加减法模式不同具体作用见下,s存结果,f用于定结果正负号,j用于定加减法模式,uh用于破字符串截取中的-0=0大坑
  17. for %%i in (1 2)do set c%%i=!c%%i:--=!&if !c%%i!==--= set c%%i=0
  18. ::因为要去掉加数的双负,不得不在setlocal后再检测加数是否定义。
  19. (for %%i in (1 2)do (for /f "tokens=* delims=0,-" %%j in ("!c%%i!")do set "c%%i=%%j")&set "$=!c%%i!#"&set N%%i=0&(for %%j in (4608 2304 1152 576 288 144 72 36 18 9)do if !$:~%%j!. NEQ . set/aN%%i+=%%j&set $=!$:~%%j!)&set $=!$!876543210&set/a$%%i=N+!$:~9,1!)&set f=%c1:~,1%&(if !f! NEQ - set f=)&(if !f!%c2:~,1%1 LSS 0 set j=-&set k=&set/au=0,v=9)&(if !$1! LSS !$2! (set f=%c2:~,1%&for %%i in (!c1!)do set c1=!c2!&set c2=%%i)else if !$1!==!$2! if !c1! LSS !c2! set f=%c2:~,1%&for %%i in (!c1!)do set c1=!c2!&set c2=%%i)&if !f! NEQ - set f=
  20. ::定号需要位数信息,所以在那之前必须除负号与开头0,但定号又需要看大数开头有没有负号,所以很麻烦。偏偏又找不到只用百分号而不引起歧义的变量嵌套。"if !f!%c2:~,1%1 LSS 0"的作用是判断c1、c2是不是只有1个是负数,是则改为减法模式。要比c1、c2大小,先比位数,位数相等则可用Bat自带if(数大时当字符串,从左往右逐位比)直接比较;c1<c2则易位。最后根据大数的正负来定结果的正负。
  21. if not defined c1 endlocal&set %~3=0&exit/b
  22. ::c1未定义,即2个数都未定义,直接结果为0然后踢回去。Bat对未定义变量的处理实在太不友好,留着后面会很烦
  23. if !$1! LSS !$2! (set c1=!c2!&set c2=%c1%
  24. )else if !$1!==!$2! if !c1! LSS !c2! set c1=!c2!&set c2=%c1%
  25. ::分成2行正常运行的代码合成一行就“输入行太长。”+“命令语法不正确。”,所以得分开
  26. if %N1% LEQ %N2% (set/aM=9+(N=%N1%^))else set/aM=9+(N=%N2%)
  27. (if %N% NEQ 0 set uh=:~,-%N%)&for /l %%i in (9 9 %N%)do set/ac=(t=1!c1:~-%%i,9!%k%+%j%1!c2:~-%%i,9!+c)/1000000000&(if !t:~^,1!==- set/at+=1000000000,c=-1)&set t=00000000!t!&set s=!t:~-9!!s!
  28. set D=0!c1:~,-%M%!&set c1=000000000!c1%uh%!&set c2=000000000!c2%uh%!&set/at=1!c1:~-9!%k%+%j%1!c2:~-9!+c&(if !t:~^,1!==- set/at+=1000000000)&set/ac=(!t:~,1!1!t:~9!-50)/50&(if %N1% NEQ %N2% set t=00000000!t!)&if !t!. NEQ 0. set s=!t:~-9!!s!
  29. (for /f "tokens=* delims=0" %%j in ("%s%")do set "s=%%j")&if not defined s set s=0&set f=
  30. ::除去s开头的0,若去完后什么都没了,说明结果为0.
  31. if %c%==0 endlocal&set %~3=%f%%D:~1%%s%&exit/b
  32. ::减法时,下面得把末尾的0去掉换成9,再把E的最后一位-1.这是变量u、v设置的原因。
  33. call :sad !D:%u%= !&set E=!E: =%u%!&set/ap=!E:~-1!+%j%1
  34. set q=!D:%E%=!&if defined q set q=!q:%u%=%v%!
  35. endlocal&set %~3=%f%%E:~1,-1%%p:0=%%q%%s%&exit/b
  36. ::%p:0=%防减法模式下E的最后一位恰好为1
  37. :sad
  38. set E=%*&exit/b
  39. :tt
  40. setlocal&set be=%1:%2
  41. for /f "delims=: tokens=1-6" %%a in ("%be:.=%")do set/at=(%%d-%%a)*360000+(1%%e-1%%b)*6000+1%%f-1%%c,t+=-8640000*("t>>31")
  42. endlocal&set %3=%t%0ms&exit/b
复制代码
除法函数:
这个除法函数限制很大,只能做到 自然数除以一个8位数以内的自然数,得到商与余数。
(不过对我来说够用了,除数根本用不到那么大)
需要更通用的除法函数,请浏览随风的http://www.bathome.net/viewthread.php?tid=3372,有一个“500位内整数除法函数”。
  1. @echo off
  2. call :chu 11212121132132132121444 44444444 a b
  3. echo %a% %b%&pause&exit
  4. :div
  5. setlocal enabledelayedexpansion&set c1=%~1&set c2=%~2&set c3=&set t=
  6. ::c1被除数,c2除数,c3储存余数,t储存商。
  7. :c
  8. set c1=%c3%%c1%&(if "!c1:~9!"=="" (set L=123456789%c1%) else set L=9876543210%c3%)&set c3=0000000!c1:~0,9!&set/ac3=1!c3:~-9!-1000000000&set c1=!c1:~9!
  9. ::第一句把余数补回到被除数前面,若补完后被除数位数≦9,则测出补回之前c1的长度(因为后面!t!截取多少关键看被除数被用掉了几位);否则测出9-c3的长度,此即被除数在此轮中被截走的位数。之后同样去除c3开头的0以准备运算,并切去新c1的9位。
  10. set/at=c3/c2,c3%%=c2&(if not "%t%"=="" set t=00000000!t!)&set t=%t%!t:~-%L:~-10,1%!&if defined c1 goto c
  11. ::计算商、余,若在此轮计算前t是已定义的(if defined会延迟变量),则给t补0(因为商前面不应该出现一串0,故第一轮不能补0)。之后截取此轮商附到之前的结果后面,具体取多少,取决于此轮c1之前被截了多少位。
  12. endlocal&set %~3=%t%&set %~4=%c3%&goto :eof
复制代码
阶乘质因子分解(随手写没啥用)
  1. @echo off&setlocal enabledelayedexpansion
  2. set/p n=请输入(0-1000):
  3. if %n% LEQ 1 (set Q=1 ) else for %%i in (2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199 211 223 227 229 233 239 241 251 257 263 269 271 277 281 283 293 307 311 313 317 331 337 347 349 353 359 367 373 379 383 389 397 401 409 419 421 431 433 439 443 449 457 461 463 467 479 487 491 499 503 509 521 523 541 547 557 563 569 571 577 587 593 599 601 607 613 617 619 631 641 643 647 653 659 661 673 677 683 691 701 709 719727 733 739 743 751 757 761 769 773 787 797 809 811 821 823 827 829 839 853 857 859 863 877 881 883 887 907 911 919 929 937 941 947 953 967 971 977 983 991 997) do (
  4.   set m=&set n=%n%&for /l %%j in (1 1 6) do set/a n/=%%i,m+=n
  5.   if !m! GTR 0 set Q=!Q!%%ix!m! )
  6. echo %Q:~0,-1%
  7. pause
复制代码
阶乘奇数降幂分解(随手写没啥用)
  1. @echo off&setlocal enabledelayedexpansion
  2. set/p n=请输入(>0):
  3. set/a b=n+(n"&"1)-1,n">>"=1
  4. :a
  5. set/a t+=1,m+=n,b=n+(n"&"1)-1,a=b+2,n">>"=1&echo 从!a!到%b%的奇数其幂为!t!
  6. if not %a%==3 goto a
  7. echo 2的幂为%m%
  8. pause
复制代码
若代码有BUG或您有什么建议或看法,请不吝赐教。谢谢。
作者: 老刘1号    时间: 2019-4-5 22:22

让我回想起了被高精度四则支配的恐惧……

可以参考:http://www.bathome.net/redirect. ... 3032&pid=195561
作者: codegay    时间: 2019-4-6 00:29

噗,我大约是因为复杂bat代码看不懂写不出,才放弃在这程度上使用BAT的。
我基本上都是劝弃BAT改用别的语言实现。
作者: 523066680    时间: 2019-4-6 09:26

如果是分享那就写分享,
如果是填坑 - 自己选的坑自己填。
  1. #include <iostream>
  2. #include <string>
  3. #include <vector>
  4. using namespace std;
  5. typedef unsigned long long int ULL;
  6. const ULL BASE = 1e8;
  7. const ULL LEN = 8;
  8. vector<int> vec_plus(const vector<int>& a, const vector<int>& b);
  9. string vec2str( const vector<int> &vec );
  10. int main(int argc, char *argv[] )
  11. {
  12.     //1000 段 99999999
  13.     vector<int> va(1000, 99999999);
  14.     vector<int> vb(1000, 99999999);
  15.    
  16.     vector <int> vc;
  17.     //1000次加法 耗时测试
  18.     for (int i = 0; i < 1000; i++) vc =vec_plus(va, vb);
  19.     cout << vec2str( vc );
  20.     return 0;
  21. }
  22. vector<int> vec_plus(const vector<int> &a, const vector<int> &b)
  23. {
  24.     static int ia; // iter
  25.     vector<int> c( a.size() );
  26.     int t, pool=0, ib = b.size()-1;
  27.     int v, r;
  28.     for (ia = a.size()-1; ia >= 0; ia-- )
  29.     {
  30.         t = ib >= 0 ? (a[ia]) + (b[ib--]) + pool : (a[ia]) + pool;
  31.         v = t % BASE, pool = t / BASE;
  32.         c[ia] = v;
  33.     }
  34.     if ( pool > 0 ) c.insert(c.begin(), pool);
  35.     return c;
  36. }
  37. string vec2str( const vector<int> &vec )
  38. {
  39.     string s("");
  40.     s += to_string( vec[0] );
  41.     for ( int it = 1; it < vec.size(); it++ )
  42.         s += to_string(vec[it]+BASE).substr(1, LEN);
  43.     return s;
  44. }
复制代码

作者: hongrk    时间: 2019-4-6 15:10

回复 2# 老刘1号


   谢谢,你所给的那个代码,我阅读过,也测试过(运算同样的内容100遍时间是一楼的4倍,1.2秒)
但发此贴不是为了寻求加法函数,而是为了求指点。比如:
①一楼的代码是否有什么考虑不周的问题?(不然我无法理解为什么那些经典代码似乎显得很冗长)
②为什么
  1. set c1=%c1:~0,-9%&set c2=%c2:~0,-9%
复制代码
一句,当c1未定义的时候把后面用&隔开的set都吃掉了变成了"~0,-9c2:~0,-9",而c2即使有定义也不会发生改变。
作者: hongrk    时间: 2019-4-6 15:12

回复 4# 523066680


  这句话是说给我听的吗?有些看不明白。
发此贴不是为了寻求加法函数,而是希望能够得到指点。比如:
①一楼的代码是否有什么考虑不周的问题?(不然我无法理解为什么那些经典代码似乎显得很冗长)
②为什么
  1. set c1=%c1:~0,-9%&set c2=%c2:~0,-9%
复制代码
一句,当c1未定义的时候把后面用&隔开的set都吃掉了变成了"~0,-9c2:~0,-9",而c2即使有定义也不会发生改变。
作者: hongrk    时间: 2019-4-6 15:14

回复 3# codegay


    只是做一个程序的时候突然想做个尽量完整些的罢了。其他无需数值计算的部分,我倒觉得Bat正好很好用。
不过还是迟早会遇到很难用Bat解决的问题啊。
作者: 523066680    时间: 2019-4-6 17:41

早就脱坑,对我个人而言,没有任何理由再讨论bat。(一句话:我走错片场了
作者: 老刘1号    时间: 2019-4-6 19:13

本帖最后由 老刘1号 于 2019-4-6 19:40 编辑

回复 5# hongrk


    哈哈,批就别比什么效率了吧,没意义。
顺便 你那个函数有bug
call :jia 1000101000100022222222222222222222222222222222222222311 1009993333333333333333333123999999

批:
60ms
1101000100022222223232215555555555555555555346222310

我的汇编版高精度四则:
1000101000100022222223232215555555555555555555346222310


至于你问的那个问题,我只能说批的机制非常奇诡,就不要纠结了

有机会的话,我逆cmd的时候,会分析一下
作者: hongrk    时间: 2019-4-6 20:46

本帖最后由 hongrk 于 2019-4-6 21:04 编辑

回复 9# 老刘1号


    谢谢指出,我已经找到原因了。是补0的问题,算1000000000+1能算出11来……修改完后我会把一楼的代码改好。
那个诡异的情况我根本没法用我所知道的东西解释……
作者: 老刘1号    时间: 2019-4-6 21:39

本帖最后由 老刘1号 于 2019-4-6 21:42 编辑

没错我又来了
1楼除法代码
200000000500002 12121244
我的高精度四则
252272727995700.2526894925268949252689492526894925268949252689492526894925268949252689492526894925268949252689492526894

顺便算了下200000000500002*44444444+12121244
高精度正负浮点数四则运算.EXE * 200000000500002 44444444
8888888822222310888888
高精度正负浮点数四则运算.EXE + 8888888822222310888888 12121244
8888888822222323010132

我的结果再算回去
高精度正负浮点数四则运算.EXE * 252272727995700.25268949252689492526894925268949252689 44444444
11212121132132132121443.99999999999999999999999999999978109916

作者: hongrk    时间: 2019-4-7 15:30

回复 11# 老刘1号


    谢谢,代码已改。
作者: hongrk    时间: 2019-4-8 23:27

回复 11# 老刘1号


    加法函数的另一个BUG也修了,现在加数调换也不会出错了,而且加数未定义或开头带0也可以正确计算。之前修得不够彻底。
    不过除法的那个开头带0是算不对的,而且两个数都不能未定义。不过这不太重要。
现在应该是2个都没有BUG了,希望不会被打脸。另外,我在代码上添了一些注释。
作者: 老刘1号    时间: 2019-4-9 00:50

本帖最后由 老刘1号 于 2019-4-9 00:57 编辑

回复 13# hongrk


    这个如果有bug的话其实是很隐蔽的,因为复杂数字人也懒得手算,除非有现成软件验证
我最初用bat写的高精度加减一直有bug,两年之后才发现(还是自己发现的,哈哈
特别是借用批处理的变量截取等做运算,感觉需要考虑的更多,
看着lz修bug有种莫名的快感,哈哈,想当年修bug修的都想砸电脑了

分享下测试用的批,不过大多不适用于lz的函数
如果以后lz写了正负浮点数四则的话,可以用这两个测试

加法测试.bat
  1. @echo off
  2. Setlocal enabledelayedexpansion
  3. ::CODER BY 老刘 POWERD BY iBAT
  4. rem 加法
  5. rem 整数
  6. rem 伪浮点数
  7. test + 00000001.0000 1.0
  8. rem 双0
  9. test + 000000000000000.0 0.0000000000000000000
  10. rem 无小数点带进位
  11. test + 2333 7667
  12. rem 浮点数
  13. rem 有间隔进位
  14. test + 1.80028 00.2007200
  15. rem 跨小数点连续进位(最后一位也进位)
  16. test + 2.73210962 7.26789038
  17. rem 减法
  18. rem 整数
  19. rem 大减小
  20. rem 负负得正
  21. test - 1 -2
  22. rem 带借位
  23. test - 2541 1542
  24. rem 小减大
  25. test + 2541 -2542
  26. rem 浮点数
  27. rem 连续借位
  28. test - 7.998253 6.998254
  29. rem 间隔借位
  30. test - 2.36291 0.37192
  31. pause
复制代码
测试-计算圆周率.BAT
  1. @Rem 公式:pi=2*1+2*1!/3!!+2*2!/5!!+2*3!/7!!+...+2*k!/(2*k+1)!!+...
  2. @echo off
  3. Setlocal enabledelayedexpansion
  4. ::CODER BY 老刘 POWERD BY iBAT
  5. Set Calc=高精度正负浮点数四则运算
  6. Title 任意键提高精度
  7. Set /a k=0,sss=1
  8. :loop
  9. Set /a k+=1,n=2*k+1
  10. Call :! !k!
  11. Set aaa=!Re!
  12. Call :!! !n!
  13. Set bbb=!Re!
  14. For /f %%b in ('!calc! / %aaa:~,93% %bbb:~,93%') Do Set ccc=%%b
  15. For /f %%b in ('!calc! + %ccc:~,93% %sss:~,93%') Do Set sss=%%b
  16. For /f %%b in ('!calc! * %sss:~,93% 2') Do Echo %%b
  17. rem Pause>nul
  18. Goto :loop
  19. :! 阶乘
  20. Set Re=1
  21. For /l %%a in (1 1 %1) Do (
  22. For /f %%b in ('!calc! * !re! %%a') Do Set Re=%%b
  23. )
  24. Goto :Eof
  25. :!! 双阶乘
  26. Set Re=1
  27. For /l %%a in (1 2 %1) Do (
  28. For /f %%b in ('!calc! * !re! %%a') Do Set Re=%%b
  29. )
  30. Goto :Eof
复制代码
2.6666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666
2.9333333333333333333333333333333333333333333333333333333333333333333333333333333333333333332
3.0476190476190476190476190476190476190476190476190476190476190476190476190476190476190476188
3.0984126984126984126984126984126984126984126984126984126984126984126984126984126984126984124
3.1215007215007215007215007215007215007215007215007215007215007215007215007215007215007215004
3.1321567321567321567321567321567321567321567321567321567321567321567321567321567321567321564
3.1371295371295371295371295371295371295371295371295371295371295371295371295371295371295371292
3.1394696806461512343865285041755629990924108571167394696806461512343865285041755629990924104
3.140578169680336862999401699092101568881754640268572157117048757915630980646460522621513333
3.1411060216013776385293413157190246973528707274837305797058119039543188149999295510131423438
3.1413584725201362703045298280188574979260132039779367818134812346684738662124582167656605662
3.141479648961140413556620313922777242201121592695155758825162513411268290794471976326869313
3.141537993173475741789108325654294156111358965040483414423379425398539680408034156856340191
3.1415661593449479692116887451108885283438873516899519378156220725648086271180296922843606148
3.1415797881375958211903566900092406439402720549074367071989652889355839239131888223301769488
3.1415863960370614463921350875357143969567010019219747772030104847517174011472053702311788076
3.1415896055882304643472845949057159341361093476147504112049752941481250900894419792116654248
3.141591166991501878487627598491122087358524218492316935854579796016647749574854383580550806
3.1415919276751469264021536771609353414925212068685672940172076302602869939395424780166744532
3.1415922987403396327019224960242588800944709572960064931209285250132817472881708167660030616
3.1415924799582244427552979657016959570861208354117326136134433805903256965979660519691635446
3.1415925685536347943369481953217763058375941091571987169653395322057694051494215002907086696
3.1415926119088356046854153289656454126734214558837034058396716915069439859299209750012520286

这个圆周率的测试其实是有问题的,如果继续算几次的话就会与实际圆周率不符,
原因是结果可以256位,输入只能93位,而输出转输入时没有做四舍五入而是直接截取,每算一次就损失一定精度。
不过做测试应该是够了,毕竟如果程序出了毛病应该连3.14都跑不出来,哈哈。
作者: hongrk    时间: 2019-4-11 22:20

回复 14# 老刘1号


    嗯……浮点也许会试着去练,但不敢说,最近事很多,搞不好什么时候就搁起来了。
之前那个加法函数还不是最好的,我后来又发现有处地方可以简化,从而把2句眼中钉的"if 未定义 则置0"删去。
比较大胆地说,我相信这应该是最好的Bat自然数加法函数了;不过也很希望被打脸见识一下。
作者: 523066680    时间: 2019-4-12 10:15

本帖最后由 523066680 于 2019-4-12 10:17 编辑

测试效率和 happy886rr 的大数加法耗时几乎一样。从代码上看,思路都是以更大的基数进行分段处理。
http://www.bathome.net/viewthrea ... mp;page=1#pid195561
  1. set num_a=456456521000210000000000000000874112115674511111111111111110019999999
  2. set num_b=923451344221111111111111111000000000001
  3. for /l %%a in (1,1,6) do set num_a=!num_a!!num_a!
  4. for /l %%a in (1,1,6) do set num_b=!num_b!!num_b!
复制代码
happy代码测试
  1. @echo off&setlocal enabledelayedexpansion
  2. title By Happy
  3. REM 大数长度
  4. set "MAX=5000" ^位
  5. REM 分割大小
  6. set "K=8"      ^位
  7. set /a CYC=MAX/K
  8. :MAIN
  9. cls
  10. set num_a=456456521000210000000000000000874112115674511111111111111110019999999
  11. set num_b=923451344221111111111111111000000000001
  12. for /l %%a in (1,1,6) do set num_a=!num_a!!num_a!
  13. for /l %%a in (1,1,6) do set num_b=!num_b!!num_b!
  14. set A=%num_a%
  15. set B=%num_b%
  16. REM 优化字符
  17. setlocal
  18. CALL :POINT !A! A N1
  19. CALL :POINT !B! B N2
  20. set /a B1=N1*K
  21. set /a B2=N2*K
  22. echo ======================================
  23. echo 被加数信息:  预估!B1!位
  24. echo   加数信息:  预估!B2!位
  25. echo ======================================
  26. echo 计算结果
  27. REM 加法核心
  28. if !N1! gtr !N2! (set RM=!N1! &set dx=B) else (set RM=!N2! &set dx=A)
  29. for /l %%i in (1 1 !RM!) do (
  30. if not defined !dx![%%i] (set "!dx![%%i]=00000000")
  31. set /a sum=1!A[%%i]!+1!B[%%i]!+sum
  32. set S=!sum:~-%K%!!S!
  33. set /a sum=!sum:~0,1!-2
  34. )
  35. REM 显示
  36. :DISP
  37. for /l %%i in (1 1 8) do (if "!S:~0,1!"=="0" (set S=!S:~1!))
  38. if "!S!"=="" (set S=0)
  39. echo,!S!
  40. endlocal
  41. goto :eof
  42. REM 分割数位
  43. :POINT
  44. set num=%1
  45. for /l %%i in (1 1 !CYC!) do (
  46. set %2[%%i]=!num:~-%K%!
  47. set num=!num:~0,-%K%!
  48. if "!num!"=="" (
  49. set /a CU=!%2[%%i]!+100000000
  50. set %2[%%i]=!CU:~-%K%!
  51. set /a %3=%%i
  52. goto :eof
  53. )
  54. )
复制代码
Sublime_text 显示的运行时间 [Finished in 0.6s]

hongrk 的测试代码
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. set num_a=456456521000210000000000000000874112115674511111111111111110019999999
  4. set num_b=923451344221111111111111111000000000001
  5. for /l %%a in (1,1,6) do set num_a=!num_a!!num_a!
  6. for /l %%a in (1,1,6) do set num_b=!num_b!!num_b!
  7. call :jia %num_a% %num_b% P
  8. echo %P%
  9. exit
  10. :jia
  11. setlocal enabledelayedexpansion&set c1=%~1&set c2=%~2&set c=0&set t=
  12. :j
  13.     if %c%==0 (
  14.         if "%c1%"=="" endlocal &set %~3=%c2%%t%&goto :eof
  15.         if "%c2%"=="" endlocal &set %~3=%c1%%t%&goto :eof
  16.     )
  17.     ::此句为“加速版”增添的代码。
  18.     set c1=000000000%c1%
  19.     set c2=000000000%c2%
  20.     set /a t=1!c1:~-9!-1000000000+1!c2:~-9!-1000000000+c,c=0&set c1=!c1:~9,-9!&set c2=!c2:~9,-9!&if "!c1!!c2!"=="" (set t=!t!%t%) else (if not "!t:~9!"=="" set c=1)&set t=00000000!t!&set t=!t:~-9!%t%&goto j
  21.     endlocal&set %~3=%t%&goto :eof
复制代码
Sublime_text 显示的运行时间 [Finished in 0.6s]
作者: 523066680    时间: 2019-4-12 12:03

本帖最后由 523066680 于 2019-4-12 21:54 编辑

循着 Modern Computer Arithmetic 的方案:

β 就是 Base,对于 int32 尺寸的容器可以选 10^9 作为 Base。

也写了一个for版本,其实和已经出现的代码都是差不多的:
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. ::constant
  4. set /a BASE=1000000000, LEN=9
  5. set MASK=!BASE:~1!
  6. ::test
  7. set num_a=456456521000210000000000000000874112115674511111111111111110019999999
  8. set num_b=923451344221111111111111111000000000001
  9. for /l %%a in (1,1,6) do set num_a=!num_a!!num_a!
  10. for /l %%b in (1,1,6) do set num_b=!num_b!!num_b!
  11. call :plus %num_a% %num_b% sum
  12. echo %sum%
  13. exit /b
  14. :plus
  15.     setlocal enabledelayedexpansion
  16.     set "sum=" & set "va=%1" & set "vb=%2"
  17.     set /a carry=0
  18.     :: 1 to 1000, because max strlen < 8192
  19.     for /l %%a in (1,1,1000) do (
  20.         set /a a=1!va:~-%LEN%, %LEN%!-BASE, b=1!vb:~-%LEN%,%LEN%!-BASE
  21.         set /a t=a+b+carry, carry=t/BASE, head=t
  22.         set t=!MASK!!t!
  23.         set va=!MASK!!va:~0,-%LEN%!
  24.         set vb=!MASK!!vb:~0,-%LEN%!
  25.         if "!va:0=!!vb:0=!" == "" (goto :next)
  26.         set sum=!t:~-%LEN%!!sum!
  27.     )
  28.     :next
  29.     endlocal&set %3=%head%%sum%&goto :eof
复制代码
Sublime_Text 显示耗时:[Finished in 0.5s]

各位大神拍砖轻点,批处理这门语言我很久都没学会,经常写出很长很臃肿的代码,所以早就换成其他语言了,语法糖很甜的那种。

补充:
    并不香,写了我也用不着。
以前的那些帖子,过去式,人家也没有那么刻意地去追求速度,实现就足够了。特别地,批处理只是批处理,有自己的定位,
一个连运算符重载都没有的脚本语言,搞四则运算,又要当坠吼的那个 —— 写到 karatsuba 乘法方案的时候你就知道烦了。

作者: 老刘1号    时间: 2019-4-12 18:48

早就脱坑,对我个人而言,没有任何理由再讨论bat。(一句话:我走错片场了
523066680 发表于 2019-4-6 17:41



    真香现场
作者: hongrk    时间: 2019-4-12 23:43

回复 17# 523066680


    出门前看到你的回帖,很想立刻回复并改进代码,但时间不够。现在补上。

Bat在效率上天生就不敌很多语言,但毕竟还有能力尽可能追求完美,当然还是想尽量写得好一些。
实用性来讲的话,我目前帖子里的加法函数和除法函数我自己就在用,正好满足需求。不过更多算是练习吧,毕竟Bat算再慢也已经比输入快了啊。

从你的代码里面意识到自己代码里还有一些可以优化的地方,比如进位符的处理,用除法比置0再检测要简洁很多。
还有一个就是那个for指令;我曾也想过用for,因为goto效率确实低些,但for循环不管怎样都要运行完 的特性实在是太不人性了。比如说算一个1+1和算几百位数加减,时间只有1倍左右的差距。happy的代码里用的是先测长度,再根据长度定循环次数,但我觉得那样的话测长度就得费很多时间了,最后还是用了最原始的goto循环。

发现call+goto可以成功跳出for循环。
代码已改进。
作者: 523066680    时间: 2019-4-13 11:42

本帖最后由 523066680 于 2019-4-13 12:24 编辑

No.1,你的第三版代码和第二版结果不一致,相同参数
作者: hongrk    时间: 2019-4-13 13:32

回复 20# 523066680


    我检查了一遍,没发现有错啊。是不是加数有变,我记不清了。
作者: 523066680    时间: 2019-4-13 14:54

本帖最后由 523066680 于 2019-4-13 16:13 编辑
  1. use List::MoreUtils qw/pairwise mesh/;
  2. my ($f1, $f2) = ("hongrk2.bat", "hongrk3.bat");
  3. my @s1 = `$f1`;
  4. my @s2 = `$f2`;
  5. my @foo = unpack("(A40)*", $s1[1]);
  6. my @bar = unpack("(A40)*", $s2[1]);
  7. printf "%40s   %40s\n", $f1, $f2;
  8. pairwise { printf "%s %s %s\n", $a, $a eq $b?" ":"!", $b } @foo, @bar;
复制代码
  1.                              hongrk2.bat                                hongrk3.bat
  2. 4564565210002100000000000000008741121156   4564565210002100000000000000008741121156
  3. 7451111111111111111001999999945645652100   7451111111111111111001999999945645652100
  4. 0210000000000000000874112115674511111111   0210000000000000000874112115674511111111
  5. 1111111100199999994564565210002100000000   1111111100199999994564565210002100000000
  6. 0000000087411211567451111111111111111001   0000000087411211567451111111111111111001
  7. 9999999456456521000210000000000000000874   9999999456456521000210000000000000000874
  8. 1121156745111111111111111100199999994564   1121156745111111111111111100199999994564
  9. 5652100021000000000000000087411211567451   5652100021000000000000000087411211567451
  10. 1111111111111110019999999456456521000210   1111111111111110019999999456456521000210
  11. 0000000000000008741121156745111111111111   0000000000000008741121156745111111111111
  12. 1111001999999945645652100021000000000000   1111001999999945645652100021000000000000
  13. 0000874112115674511111111111111110019999   0000874112115674511111111111111110019999
  14. 9994564565210002100000000000000008741121   9994564565210002100000000000000008741121
  15. 1567451111111111111111001999999945645652   1567451111111111111111001999999945645652
  16. 1000210000000000000000874112115674511111   1000210000000000000000874112115674511111
  17. 1111111111100199999994564565210002100000   1111111111100199999994564565210002100000
  18. 0000000000087411211567451111111111111111   0000000000087411211567451111111111111111
  19. 0019999999456456521000210000000000000000   0019999999456456521000210000000000000000
  20. 8741121156745111111111111111100199999994   8741121156745111111111111111100199999994
  21. 5645652100021000000000000000087411211567   5645652100021000000000000000087411211567
  22. 4511111111111111110019999999456456521000   4511111111111111110019999999456456521000
  23. 2100000000000000008741121156745111111111   2100000000000000008741121156745111111111
  24. 1111111001999999945645652100021000000000   1111111001999999945645652100021000000000
  25. 0000000874112115674511111111111111110019   0000000874112115674511111111111111110019
  26. 9999994564565210002100000000000000008741   9999994564565210002100000000000000008741
  27. 1211567451111111111111111001999999945645   1211567451111111111111111001999999945645
  28. 6521000210000000000000000874112115674511   6521000210000000000000000874112115674511
  29. 1111111111111100199999994564565210002100   1111111111111100199999994564565210002100
  30. 0000000000000087411211567451111111111111   0000000000000087411211567451111111111111
  31. 1110019999999456456521000210000000000000   1110019999999456456521000210000000000000
  32. 0008741121156745111111111111111100199999   0008741121156745111111111111111100199999
  33. 9945645652100021000000000000000087411211   9945645652100021000000000000000087411211
  34. 5674511111111111111110019999999456456521   5674511111111111111110019999999456456521
  35. 0002100000000000000008741121156745111111   0002100000000000000008741121156745111111
  36. 1111111111001999999945645652100021000000   1111111111001999999945645652100021000000
  37. 0000000000874112115674511111111111111110   0000000000874112115674511111111111111110
  38. 0199999994564565210002100000000000000008   0199999994564565210002100000000000000008
  39. 7411211567451111111111111111001999999945   7411211567451111111111111111001999999945
  40. 6456521000210000000000000000874112115674   6456521000210000000000000000874112115674
  41. 5111111111111111100199999994564565210002   5111111111111111100199999994564565210002
  42. 1000000000000000087411211567451111111111   1000000000000000087411211567451111111111
  43. 1111110019999999456456521000210000000000   1111110019999999456456521000210000000000
  44. 0000008741121156745111111111111111100199   0000008741121156745111111111111111100199
  45. 9999945645652100021000000000000000087411   9999945645652100021000000000000000087411
  46. 2115674511111111111111110019999999456456   2115674511111111111111110019999999456456
  47. 5210002100000000000000008741121156745111   5210002100000000000000008741121156745111
  48. 1111111111111001999999945645652100021000   1111111111111001999999945645652100021000
  49. 0000000000000874112115674511111111111112   0000000000000874112115674511111111111112
  50. 0334713442205675676321113210000000000019   0334713442205675676321113210000000000019
  51. 2432545633678562222222222211111002000192 ! 2432545633678562222222222211111001900192
  52. 2907800742111321111111111000000874114039 ! 2907800742111321111111111000000874114038
  53. 1258553322222222222211309999994564584444 ! 1258553322222222222211309999994564574444
  54. 5155422111111111111198511211567451303456   5155422111111111111198511211567451303456
  55. 2455332221131111110567456521000211923451   2455332221131111110567456521000211923451
  56. 3442211119852232267855111111111130345613 ! 3442211119852232267855111111111120345613
  57. 6422111056756763211121000000000192345221 ! 6322111056756763211121000000000192345121
  58. 8333226785622222222111111110021923450800 ! 8333226785622222222111111110021922450800
  59. 6776321113211111110000000008760355670187 ! 6776321113211111110000000008750355670187
  60. 3222222222222222101999999945837997234443   3222222222222222101999999945837997234443
  61. 1111111111111111874112115676434562455332   1111111111111111874112115676434562455332
  62. 2222211311111104564565210021334513442211 ! 2222211301111104564565210011334513442211
  63. 1111198522322667451111111303456245424111   1111198522322667451111111303456245424111
  64. 1110567567632000210000001923451345095223 ! 0110567567632000210000001923451345095223
  65. 2267856222221111111111119434513436775676   2267856222221111111111119434513436775676
  66. 3211132111100000000000279756345989562222   3211132111100000000000279756345989562222
  67. 2222222222110020000001379907865221321111 ! 2222222222110019000001379907865221321111
  68. 1111111110008741121175979624553322222222 ! 1111111110008741121165979624553322222222
  69. 2113111099945645652292366134422111111111   2113111099945645652292366134422111111111
  70. 1985223115674511113034562455331131111110   1985223115674511113034562455331131111110
  71. 5675675210002100019234513442219852232267   5675675210002100019234513442219852232267
  72. 8562211111111111303347134422056756763211 ! 8562211111111111303347034422056756763211
  73. 1321000000000001924325456336785622222222 ! 1321000000000001923325456336785622222222
  74. 2221111100200019229078007421113211111111 ! 2221111100200009229078007421113211111111
  75. 1100000087411403912585533222222222222113   1100000087411403912585533222222222222113
  76. 0999999456458444451554221111111111111985   0999999456458444451554221111111111111985
  77. 1121156745130345624553322211311111105674 ! 1121156745120345624553322211301111105674
  78. 5652100021192345134422111198522322678551   5652100021192345134422111198522322678551
  79. 1111111113034561364221110567567632111210 ! 1111111113034561364220110567567632111210
  80. 0000000019234522183332267856222222221111   0000000019234522183332267856222222221111
  81. 1111002192345080067763211132111111100000   1111002192345080067763211132111111100000
  82. 0000876035567018732222222222222221019999   0000876035567018732222222222222221019999
  83. 9994583799723444311111111111111118741121 ! 9994573799723444311111111111111118741121
  84. 1567643456245533222222113111111045645652 ! 1567643456245533222222113111011045645652
  85. 1002133451344221111111985223226674511111   1002133451344221111111985223226674511111
  86. 1130345624542411111105675676320002100000 ! 1120345624542411111105675676320002100000
  87. 0192345134509522322678562222211111111111   0192345134509522322678562222211111111111
  88. 1943451343677567632111321111000000000002 ! 1942451343677567632111321111000000000001
  89. 7975634598956222222222222221100200000013 ! 7975634598956222222222222221100199990013
  90. 7990786522132111111111111100087411211759   7990786522132111111111111100087411211759
  91. 7962455332222222221131110999456456522923   7962455332222222221131110999456456522923
  92. 6613442211111111119852231156745111130345   6613442211111111119852231156745111130345
  93. 6245533113111111056756752100021000192345 ! 6245533113011111056756752100021000192345
  94. 1344221985223226785622111111111113033471 ! 1344221985223226785622111111111112033471
  95. 3442205675676321113210000000000019243254 ! 3432205675676321113210000000000019243254
  96. 5633678562222222222211111002000192290780   5633678562222222222211111002000192290780
  97. 0742111321111111111000000874114039125855 ! 0742111321111111111000000874113039125855
  98. 3322222222222211309999994564584444515542   3322222222222211309999994564584444515542
  99. 2111111111111198511211567451303456245533   2111111111111198511211567451303456245533
  100. 2221131111110567456521000211923451344221 ! 2221131110110567456521000211923451344221
  101. 1119852232267855111111111130345613642211   1119852232267855111111111130345613642211
  102. 1056756763211121000000000192345221833322   1056756763211121000000000192345221833322
  103. 6785622222222111111110021923450800677632 ! 6785622222222111111110020923450800677632
  104. 1113211111110000000008760355670187322222 ! 1113211111110000000008760355660187322222
  105. 2222222222101999999945837997234443111111   2222222222101999999945837997234443111111
  106. 1111111111874112115676434562455332222221 ! 1111111111874112115675434562455332222221
  107. 1311111104564565210021334513442211111119   1311111104564565210021334513442211111119
  108. 8522322667451111111303456245424111111056 ! 8522322667451111111303456245424011111056
  109. 7567632000210000001923451345095223226785 ! 7567632000210000001923451344095223226785
  110. 6222221111111111119434513436775676321113 ! 6222221111111111119434503436775676321113
  111. 2111100000000000279756345989562222222222   2111100000000000279756345989562222222222
  112. 2222110020000000   2222110020000000
复制代码

作者: 523066680    时间: 2019-4-13 21:16

本帖最后由 523066680 于 2019-4-13 21:48 编辑

写了一个很冗长的版本,按之前的测试数值 4416位数 + 2496位数,耗时200ms
顺带用其他脚本写了一个效率和准确性测试,
  1. use Time::HiRes qw/time/;
  2. use bigint 'a'=>9000;
  3. STDOUT->autoflush(1);
  4. srand(1);
  5. for (1..50) { check() }
  6. sub check
  7. {
  8.     my $a = int(rand(9))+1 .join "", map { int(rand(10)) } ( 1 .. rand(4100) );
  9.     my $b = int(rand(9))+1 .join "", map { int(rand(10)) } ( 1 .. rand(4100) );
  10.     if ( length($b) > length($a) ) { ($a, $b) = ($b, $a); }
  11.     my $ta = time();
  12.     my $res = `plus_vec4.bat $a $b`;
  13.     my $dt = time()-$ta;
  14.     my $check = (0+$a)+$b;
  15.     $res =~s/\r?\n$//;
  16.     if ( $res eq $check ) {
  17.         printf "%4d, %4d, correct, %.2f\n", length($a), length($b), $dt;
  18.     } else {
  19.         printf "%4d, %4d, wrong, %.2f\n", length($a), length($b), $dt;
  20.     }
  21. }
复制代码
左边是两个数值的长度,最右是耗时
  1. 3327, 1864, correct, 0.17s
  2. 2627, 2125, correct, 0.13s
  3. 4067, 1529, correct, 0.20s
  4. 3224,  558, correct, 0.16s
  5. 1716,    7, correct, 0.08s
  6. 4056, 3309, correct, 0.22s
  7. 2429,  566, correct, 0.12s
  8. 717,  443, correct, 0.04s
  9. 3880, 2849, correct, 0.20s
  10. 2459,   95, correct, 0.12s
  11. 1212,  998, correct, 0.06s
  12. 3908, 1325, correct, 0.19s
  13. 3219,  392, correct, 0.15s
  14. 3483, 1089, correct, 0.17s
  15. 137,    9, correct, 0.04s
  16. 2306, 2297, correct, 0.12s
  17. 2308, 1083, correct, 0.12s
  18. 3207, 1677, correct, 0.16s
  19. 1919, 1862, correct, 0.09s
  20. 1071,   14, correct, 0.05s
  21. 3823, 3439, correct, 0.20s
  22. 3750,  448, correct, 0.18s
  23. 2067, 1724, correct, 0.10s
  24. 1565, 1469, correct, 0.07s
  25. 2388, 2052, correct, 0.12s
  26. 2271, 1209, correct, 0.11s
  27. 2642,  403, correct, 0.12s
  28. 2352, 1198, correct, 0.11s
  29. 4087, 2076, correct, 0.21s
  30. 1917,  349, correct, 0.08s
  31. 3579,  882, correct, 0.17s
  32. 2276, 1315, correct, 0.11s
  33. 3243, 2225, correct, 0.17s
  34. 735,  543, correct, 0.04s
  35. 3111, 2193, correct, 0.16s
  36. 2992, 1849, correct, 0.15s
  37. 3672, 3562, correct, 0.20s
  38. 3729, 1593, correct, 0.18s
  39. 4000, 3199, correct, 0.22s
  40. 3888, 2476, correct, 0.20s
  41. 2899, 1969, correct, 0.15s
  42. 2548, 1586, correct, 0.13s
  43. 3407,  383, correct, 0.16s
  44. 2608,  210, correct, 0.13s
  45. 4022,  792, correct, 0.19s
  46. 4022, 1176, correct, 0.20s
  47. 3376, 2227, correct, 0.17s
  48. 1978,   84, correct, 0.09s
  49. 1510,  304, correct, 0.07s
  50. 2602, 1592, correct, 0.13s
复制代码
最后,随手写一个 50000 位随机数相加,我写的很冗长
  1. use bigint;
  2. srand(1);
  3. my $gener = sub { int(rand(9))+1 .join "", map {int(rand(10))} (2 .. shift) };
  4. my $a = $gener->(50000);
  5. my $b = $gener->(50000);
  6. print 0+$a+$b;
复制代码

作者: hongrk    时间: 2019-4-13 22:24

回复 22# 523066680


    第二版试了好几次,都是提示过长闪退,不知道具体结果多少。不过在你给出的2个结果中,第三版的那个是对的,是第二版错了。

自然,其他语言快得多也方便得多;但目前我还只想先练好Bat。发出来主要还是想让别人指出问题方便改进,而这点基本达到了。肯定迟早会去试着用其他语言,但顺其自然吧。至少先把手头的做掉
作者: hongrk    时间: 2019-4-22 00:22

回复 22# 523066680


    后来更新的时候发现确实是有问题,很抱歉。不过已经处理好了。
二分法数位数的效率极佳,而goto循环的效率极差,二者相较下,采取数位以便改用for循环才是最合适的,我之前的想法有些偏颇。
改写后的代码计算之前那个例子,1次所需时间在110-120ms左右,有四五倍的提升。




欢迎光临 批处理之家 (http://www.bathome.net/) Powered by Discuz! 7.2