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

[数值计算] [代码讨论]批处理开平方(计算平方根的值)

本帖最后由 SQYSQYSQY 于 2019-1-29 18:40 编辑

致浏览者,想对大数字(超过1000)计算平方根,请见31楼(约18秒算到150位),想对小数计算平方根,请见34楼(是个文件)(约23秒算到150位)
注意,部分计算器对最后一位进行了四舍五入,本程序可能会与计算器的最后一位相差1。这不是本程序的错误。
致浏览者,被开方数不超过1000,可用下面高效率程序进行计算(约3.5秒算到150位)。
  1. @echo off & SetLocal EnableDelayedExpansion
  2. ::变量c的值是被开方数,不得超过1000!
  3. set c=2
  4. for %%a in (16 8 4 2 1) do (
  5.         set /a "d=(a*%%a<<1)+%%a*%%a+b"
  6.         if !c! geq !d! set /a "a+=%%a","b=d"
  7. )
  8. if !b! equ !c! echo !a! & pause & exit /b
  9. set /p "=!a!."<nul
  10. set "d=0"
  11. for %%a in (512 256 128 64 32 16 8 4 2 1) do (
  12.         set /a "d+=%%a","e=((a*d<<1)+d*d/1000)/1000+b"
  13.         if !e! geq !c! set /a "d-=%%a"
  14. )
  15. set "e=00!d!" & set /p "=!e:~-3!"<nul
  16. set /a "e=(!a!!e:~-3!*!a!!e:~-3!)%%1000000","b=e/1000","e=e%%1000"
  17. set "e=  !e!" & set "e=!e:~-3!"
  18. set "b=000!e!!b!"
  19. set "e=  !d!"
  20. set "a=!e:~-3!!a!"
  21. for /l %%a in (3 3 2147483646) do (
  22.         set "d=0"
  23.         for %%b in (512 256 128 64 32 16 8 4 2 1) do (
  24.                 set /a "d+=%%b"
  25.                 if 1000 gtr !d! (
  26.                         set /a "c=d*d/1000"
  27.                         for /l %%c in (0 3 %%a) do set /a "c=((!a:~%%c,3!*d<<1)+c+!b:~%%c,3!)/1000"
  28.                         set /a "e=%%a+3"
  29.                         for %%c in (!e!) do set /a "c+=!b:~%%c,3!" & if !c! geq 1000 set /a "d-=%%b"
  30.                 ) else set /a "d-=%%b"
  31.         )
  32.         set "e=00!d!" & set /p "=!e:~-3!"<nul
  33.         set "c=" & set /a "f=d*d/1000"
  34.         for /l %%b in (0 3 %%a) do (
  35.         set /a "e=(!a:~%%b,3!*d<<1)+!b:~%%b,3!+f","f=e/1000","e%%=1000"
  36.         set "e=  !e!" & set "c=!c!!e:~-3!"
  37.         )
  38.         set /a "e=(d*d)%%1000" & set "e=  !e!" & set "b=000!e:~-3!!c!"
  39.         set "e=  !d!" & set "a=!e:~-3!!a!"
  40. )
  41. echo. & pause & exit /b
复制代码
1

评分人数

这是牛顿迭代法吗?

TOP

bug是有的,比如计算87的平方根,精确到小数点后1000位,不到100位就出错了.

TOP

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

山的那边海的那边有一群小升初的学生已经在用 JAVA PHP JS做网站写算法,做麻省理工的数学题,
每天 RNN,DNN,KNN, A*, 神经网络,深度学习,区块链

楼主还是可以再加强一个。

TOP

本帖最后由 523066680 于 2018-12-16 10:57 编辑

牛顿迭代法参考:http://www.matrix67.com/blog/archives/361
在支持浮点数加减乘除的环境下,牛顿迭代法比一般方案要高效得多,仅仅是线性地迭代就可以增加精确度。

这种出现多个反复goto,变量命名使用极限缩写的批处理可读性实在不好,所以我估计论坛也没有那么多闲人去充当“人肉解释器”。
在轻度阅读后的一些无关痒痛的关于可读性的建议(如果是想让别人阅读自己的代码并提出建议,而不是单纯的发布作品的话)
  1. :next
  2.     cls
  3.     if "%number%"=="" goto start
  4.     set /a temp=%number%+0
  5.     if not "%temp%"=="%number%" goto error_a
  6.     if not %number% geq 0 goto error_b
  7.     if %number% geq 2147483647 goto error_c
  8.     goto then
复制代码
这个 :next 代码块是用来获取被开方数的,不妨命名为  :GetNum 或者 :get_number
  1. :then
  2.     cls
  3.     echo.&echo 请输入精确位数,然后按回车键:
  4.     echo (指精确到小数点后第几位)
  5.     echo (该程序不会对最后一位进行四舍五入)
  6.     echo (精确位数最高为238609294,超出范围,会计算出错)
  7.     echo (对于结果为整数的,程序会舍去小数部分)
  8.     set bit=
  9.     set /p "bit="
  10.     goto other
复制代码
:then 代码块是用来输入精度的,不妨命名为 :set_precision (找谷歌翻译的)

这样在 ther :error_a(b/c/d/e) 中的 goto then/next 变成 goto get_number/set_precision,就很清楚是要重新获取输入。(谁还记着 then 和 next 是干什么的?)
而 :other 可以叫做 :check_precision

以及 StringLenth 按理说应该叫 StringLength

代码中还有各种  temp  nun num tga tgb tgc tgd 变量名到处“穿越”,可否改成具体含义的名称(可以谷歌翻译呀)?

TOP

本帖最后由 523066680 于 2018-12-16 13:02 编辑

回复 9# SQYSQYSQY

    我已经在修改和调整,改好再放出来。给标签和变量一个好的名称并不会占用多少空间,而可读性和可维护性会大大提高。
贴前面提到的一小部分
      :start
          echo.&echo 请输入被开方数(仅限整数),然后按回车键:
          echo (被开方数最高为2147483646,超出范围,会计算出错)
          set number=
          set /p "number="
          goto get_number

      :get_number
          cls
          if "%number%"=="" goto start
          set /a temp=%number%+0
          if not "%temp%"=="%number%" goto error_a
          if not %number% geq 0 goto error_b
          if %number% geq 2147483647 goto error_c
          goto set_precision

      :set_precision
          cls
          echo.&echo 请输入精确位数,然后按回车键:
          echo (指精确到小数点后第几位)
          echo (该程序不会对最后一位进行四舍五入)
          echo (精确位数最高为238609294,超出范围,会计算出错)
          echo (对于结果为整数的,程序会舍去小数部分)
          set bit=
          set /p "bit="
          goto chk_precision

      :chk_precision
          cls
          if "%bit%"=="" goto then
          set /a temp=%bit%+0
          if not "%bit%"=="%temp%" goto error_d
          if not %bit% geq 0 goto error_d
          if %bit% geq 238609295 goto error_e
          set start=yes
          goto main


保存文件的代码中 多个echo 可以用括号合并,使代码更简洁
      :save_and_exit
          if "%bit%"=="0" (
              set info=(保留整数)
          ) else (
              set info=(精确到小数点后第%bit%位)
          )
          cd /d "%UserProfile%\desktop"
          set fname="%number%的平方根的结果%info%.txt"
          rem 若存在同名文件,获取权限
          if exist %fname% takeown %fname%
         
          >%fname% (
              echo %number%的平方根的结果:
              echo %info%
              echo (未对其结果进行四舍五入):
              echo %nun%
          )
          goto exit


一个很明显的问题:当程序达到“大规模”、存在上亿变量运算的时候,
别的语言多么省事省心,可以分为多个模块,可以写类,不需要各种goto往返,结构清晰,为什么还要用批处理呢?
其他语言可以多线程,并行,甚至可以利用显卡(CUDA OpenCL)计算单元实现高效并行,而批处理…… 只是你编程路上的一个节点。

试想一下这种动图如果用批处理去计算每个像素点,要耗时多久。
独显+Shader,1920*1080分辨率,每个像素的计算存在数百上千次迭代,每秒可以达到30帧:1920*1080像素*100次循环*30帧

(有关这个图像可以参考 http://www.matrix67.com/blog/archives/292 可以只做了解,高中后就会学到相关知识。)

扯远了,退一步说,不管用什么语言,清晰的函数命名、变量命名、模块化才有利于构建更大的程序。否则可能源码还未达到1MB就写不下去了。
1

评分人数

    • SQYSQYSQY: 数学与图形结合,效果真好技术 + 1

TOP

本帖最后由 523066680 于 2018-12-17 22:19 编辑

:kfmain 的轻度简化
这些常量列表可以创建到一个叫 :init 的函数中,只在开始的时候初始化一次,不会有什么开销。
  1. :kfmain
  2.     set /a u+=1
  3.     rem 设置常量映射表
  4.     set ER_2m=1
  5.     set ER_5m=2
  6.     set ER_4m=3
  7.     set ER_2l=4
  8.     set   U_1=5
  9.     set ER_7m=6
  10.     set ER_5l=7
  11.     set ER_9m=8
  12.     set ER_7l=9
  13.    
  14.     if defined ER_%er% (
  15.         set %kfmain%=!ER_%er%!
  16.         goto bignum_mp
  17.     )
  18.    
  19.     if defined U_%u% (
  20.         set %kfmain%=!U_%u%!
  21.         goto bignum_mp
  22.     )
  23.    
  24.     if "%er%"=="1m" set temp=0
  25.     if "%er%"=="1l" set temp=1
  26.     if "%er%"=="3m" set temp=2
  27.     if "%er%"=="3l" set temp=3
  28.     if "%er%"=="4l" set temp=4
  29.     if "%er%"=="6m" set temp=5
  30.     if "%er%"=="6l" set temp=6
  31.     if "%er%"=="8m" set temp=7
  32.     if "%er%"=="8l" set temp=8
  33.     if "%er%"=="9l" set temp=9
  34.     goto :eof
复制代码
因为末尾的值是序列递增的,在创建列表的时候甚至可以用for,进一步缩减代码(同上面理由一样,放在初始化函数中不会有什么效率影响),但是不建议这么做因为可读性超差
  1. :kfmain
  2.     set /a u+=1
  3.     rem 设置常量映射表
  4.     set /a iter = 1
  5.     for %%a in ( E_2m E_5m E_4m E_2l U_1 E_7m E_5l E_9m E_7l ) do (
  6.         set /a %%a=iter, iter+=1
  7.     )
  8.     set /a iter = 0
  9.     for %%a in ( 1m 1l 3m 3l 4l 6m 6l 8m 8l 9l ) do (
  10.         set /a T_%%a=iter, iter+=1
  11.     )
  12.    
  13.     if defined E_%er% (
  14.         set /a %kfmain% = E_%er%
  15.         goto bignum_mp
  16.     )
  17.    
  18.     if defined U_%u% (
  19.         set /a %kfmain% = U_%u%
  20.         goto bignum_mp
  21.     )
  22.     if defined T_%er% set /a temp=T_%er%
  23.     goto :eof
复制代码
um...  bignum_mp 就是 bignum multiply 的意思

TOP

本帖最后由 523066680 于 2018-12-19 17:46 编辑

计算字符串长度,这里有个超完整的合集
[代码合集] [更新]求字符串长度,简短高效的批处理代码(多种算法)
(里面有我08年的老贴链接,以前真是语无伦次。)

因为楼主的被开根数受到批处理最大整数限制(10位以内),所以这个方法很好用
http://www.bathome.net/redirect.php?goto=findpost&ptid=1249&pid=26990
  1. @echo off
  2. set test_num=314159
  3. set temp_str=%test_num%fedcba9876543210
  4. set /a len=0x%temp_str:~15,1%
  5. echo %len%
复制代码

TOP

本帖最后由 523066680 于 2018-12-20 14:13 编辑

回复 14# SQYSQYSQY

    在处理字符串的时候如果出现 & 或者 ()^ 都有可能造成字符串的某一部分被当作代码执行。
特别是提取的时候,那些裸的控制符号容易造成“攻击”。(不过我已经举不出具体的例子了,很久没用过批处理)
还有一些查表法掺入特殊字符作为标记,如果我在测试字符串也加入这些特殊字符,就会造成混淆。

打算另外写一个粗略的实现(不管细节),搞完这波再也不碰批处理了,不划算。

有一个优化方向:
假设当前的进展是:精确到了8个有效数字,m 约等于 a*a,a包含8位有效数字
假设是88888888,这个数的平方是已经知道了的
迭代到下一位数字b的时候,假设b是6,那么就需要计算 (88888888*10+6)^2 。
这个公式展开  (a*10+b)^2
= a^2*100 + 2*a*b + b^2
a^2 是上一步已经知道的,*100 直接后面加两个0,
2*a*b 比大数乘法简单,是大数*单个数*2,
b^2可以直接set/a得到

TOP

本帖最后由 523066680 于 2018-12-21 19:01 编辑

初步实现。支持大数(整数)开根,小数精确到80位耗时30秒。每个函数各自独立,没有跨函数穿越的 goto。

:init 初始化常量模板(用于计算字符串长度)
:get_int_of_root 获取根的整数部分
:get_dec_of_root 获取根的小数部分
:bignum_mp 大数乘法
:bignum_plus 加法
:bignum_minus 减法
:bignum_div_single 除法(除以单个数字)
:cmp %str1% %str2% %vname% 大数比较,返回值为 -1, 0, 1 之一
:time_used %time_a% %time_b% 粗略计算秒钟消耗

整数部分的开根用大范围二分搜索,例如判断整数根是5位数 min=10000 max=99999 mid=(min+max)/2 三个变量迭代(实际用bignum系列函数计算,消耗还挺大)
浮点数的部分用了上一楼提到的方法,已知某一层结果 a^2 = square (≈ num)
精确到下一位数字的时候可以省去部分的计算,%a%%b% ^ 2 相当于 (a*10+b)^2
展开后 = a^2*100 + 2*(a*10)*b + b^2,
其中 a^2*100 可以直接用 %square%00 表示,
当a达到一定长度的时候,这些建立在之前基础上的计算,比两个相同长度的大数相乘要快得多。
  1. :: Bignum(integer) Square Root
  2. :: 523066680/vicyang
  3. :: 2018-12
  4. @echo off
  5. setlocal enabledelayedexpansion
  6. :init
  7.     rem template for counting string length
  8.     set mod=
  9.     set /a maxlen=2000, half=maxlen/2
  10.     for /l %%a in (1,1,%half%) do set mod=!mod!##
  11.     set time_a=%time%
  12. set num=123456787654322
  13. rem set num=10
  14. call :get_int_of_root %num% int_root cmp
  15. if %cmp% equ 0 (
  16.     set root=%int_root%
  17.     echo num = %num%, root = !root!, !cmp!
  18.     exit /b
  19. )
  20. set precision=80
  21. call :check_first %num% %precision%
  22. call :get_dec_of_root %num% %int_root% %precision% dec_root
  23. call :time_used %time_a% %time%
  24. exit /b
  25. :check_first
  26.     perl -Mbignum=p,-%2 -le "print sqrt(%1)" 2>nul
  27.     goto :eof
  28. :get_dec_of_root
  29.     setlocal
  30.     set num=%1
  31.     set int_root=%2
  32.     set precision=%3
  33.     set root=%int_root%
  34.     rem Show int_root first
  35.     set /p inp="%int_root%."<nul
  36.     call :bignum_mp %root% %root% prev_pow
  37.     set /a dec_len=0
  38.     :decroot_lp
  39.     set /a min=0, max=10, mid=(max+min)/2, quit = 0, dec_len+=1
  40.     :decroot_bin_search
  41.         rem calc [a*10]^2 + 2*[a*10]*b + b^2, part1 part2 part3
  42.         set /a sum = 0
  43.         set part1=%prev_pow%00
  44.         set /a part3 = mid * mid
  45.         set /a double_mid = mid * 2
  46.         call :bignum_mp %root%0 %double_mid% part2
  47.         call :bignum_plus %part1% %part2% sum
  48.         call :bignum_plus %sum% %part3% sum
  49.         rem compare
  50.         call :cmp %sum% %num%00 cmp
  51.         rem echo %root%%mid% %sum% %num%00 min:%min% max:%max% %cmp%
  52.         set /a range=max-min
  53.         if %cmp% gtr 0 ( set /a max=mid )
  54.         if %cmp% lss 0 ( set /a min=mid )
  55.         if %cmp% equ 0 ( set /a quit=1 )
  56.         if %range% leq 1 ( set /a quit=1 )
  57.         set /a mid=(max+min)/2
  58.     if %quit% equ 0 goto :decroot_bin_search
  59.     set prev_pow=%sum%
  60.     set root=%root%%mid%
  61.     set num=%num%00
  62.     set /p inp="%mid%"<nul
  63.     if %dec_len% lss %precision% goto :decroot_lp
  64.     echo,
  65.     endlocal
  66.     goto :eof
  67. :get_int_of_root
  68.     rem get the integer part of root
  69.     setlocal
  70.     set num=%1
  71.     call :length %num% len
  72.     rem initial min and max number
  73.     set /a min = 1, max = 10, root_len = len / 2 + len %% 2
  74.     for /l %%n in (2,1,%root_len%) do (set min=!min!0& set max=!max!9)
  75.     call :bignum_plus %min% %max% sum
  76.     rem middle_number = sum / 2
  77.     call :bignum_div_single %sum% 2 mid
  78.    
  79.     set /a quit = 0
  80.     :binary_search
  81.         call :bignum_mp %mid% %mid% product
  82.         call :cmp %product% %num% cmp
  83.         call :bignum_minus %max% %min% range
  84.         if !cmp! equ 0 (
  85.             set /a quit = 1, cmp=0
  86.         ) else (
  87.             if !cmp! gtr 0 (
  88.                 set max=!mid!
  89.                 set cmp=1
  90.             )   
  91.             if !cmp! lss 0 (
  92.                 set min=!mid!
  93.                 set cmp=-1
  94.             )
  95.             call :bignum_plus !max! !min! sum
  96.             call :bignum_div_single !sum! 2 mid
  97.             rem Using !var!, because we are inside the brackets
  98.         )
  99.         if %range% leq 1 (set quit=1)
  100.     if %quit% == 0 goto :binary_search
  101.     endlocal &set %2=%mid%& set %3=%cmp%
  102.     goto :eof
  103. :bignum_mp
  104.     setlocal
  105.     set num_a=%1
  106.     set num_b=%2
  107.     call :length %num_a% len_a
  108.     call :length %num_b% len_b
  109.     for /l %%b in ( 1, 1, %len_b% ) do ( set ele_b=!ele_b! !num_b:~-%%b,1! )
  110.     for /l %%a in ( 1, 1, %len_a% ) do ( set ele_a=!ele_a! !num_a:~-%%a,1! )
  111.     rem for /l %%a in (0, 1, %attemplen%) do set buff[%%a]=0
  112.     set /a id = 0, sid = 0, maxid = 0
  113.     for %%b in ( %ele_b% ) do (
  114.         set /a sid = id, id += 1
  115.         for %%a in ( %ele_a% ) do (
  116.             set /a buff[!sid!] += %%a * %%b, sid += 1, maxid = sid
  117.         )
  118.     )
  119.     rem Merge
  120.     set /a id = 0
  121.     for /l %%c in ( 0, 1, %maxid% ) do (
  122.         set /a next = %%c+1
  123.         set /a buff[!next!] += buff[%%c]/10, buff[%%c] = buff[%%c] %% 10
  124.     )
  125.     if "!buff[%maxid%]!" == "0" set /a maxid-=1
  126.     set product=
  127.     for /l %%n in (%maxid%, -1, 0) do set product=!product!!buff[%%n]!
  128.     endlocal &set %3=%product%
  129.     goto :eof
  130. :bignum_plus
  131.     setlocal
  132.     set num_a=%1
  133.     set num_b=%2
  134.     call :length %num_a% len_a
  135.     call :length %num_b% len_b
  136.     set /a max = len_a
  137.     if %len_b% gtr %len_a% (set /a max=len_b, len_b=len_a&set num_a=%num_b%&set num_b=%num_a%)
  138.     for /l %%n in ( 1, 1, %max% ) do (
  139.         if %%n leq %len_b% (
  140.             set /a buff[%%n] = !num_a:~-%%n,1! + !num_b:~-%%n,1!
  141.         ) else (
  142.             set buff[%%n]=!num_a:~-%%n,1!
  143.         )
  144.     )
  145.     set /a id = 0
  146.     for /l %%c in ( 0, 1, %max% ) do (
  147.         set /a next = %%c+1
  148.         set /a buff[!next!] += buff[%%c]/10, buff[%%c] = buff[%%c] %% 10
  149.     )
  150.     if "!buff[%next%]!" gtr "0" set /a max+=1
  151.     set sum=
  152.     for /l %%a in (%max%, -1, 1) do set sum=!sum!!buff[%%a]!
  153.     endlocal &set %3=%sum%
  154.     goto :eof
  155. :bignum_minus
  156.     setlocal
  157.     set num_a=%1
  158.     set num_b=%2
  159.     call :length %num_a% len_a
  160.     call :length %num_b% len_b
  161.     set /a max = len_a
  162.     if %len_b% gtr %len_a% (set /a max=len_b, len_b=len_a&set num_a=%num_b%&set num_b=%num_a%)
  163.     set /a minus = 0
  164.     for /l %%n in ( 1, 1, %max% ) do (
  165.         if %%n leq %len_b% (
  166.             set /a dt = !num_a:~-%%n,1! - !num_b:~-%%n,1! - minus
  167.         ) else (
  168.             set /a dt = !num_a:~-%%n,1! - minus
  169.         )
  170.         if !dt! lss 0 (
  171.             set /a buff[%%n] = dt + 10, minus=1
  172.         ) else (
  173.             set /a buff[%%n] = dt, minus=0
  174.         )
  175.     )
  176.     set delta=#
  177.     for /l %%a in (%max%, -1, 1) do set delta=!delta:#0=#!!buff[%%a]!
  178.     endlocal &set %3=%delta:#=%
  179.     goto :eof
  180. :bignum_div_single
  181.     setlocal
  182.     set num_a=%1
  183.     set num_b=%2
  184.     call :length %num_a% len_a
  185.     set /a max = len_a, mod = 0
  186.     for /l %%n in ( %len_a%, -1, 1 ) do (
  187.         set /a e = !num_a:~-%%n,1! + mod*10
  188.         set /a buff[%%n] = e/num_b, mod = e %% num_b
  189.     )
  190.     if !buff[%max%]! == 0 (set /a max-=1)
  191.     set quotaint=
  192.     for /l %%a in (%max%, -1, 1) do set quotaint=!quotaint!!buff[%%a]!
  193.     endlocal &set %3=%quotaint%
  194.     goto :eof
  195. :length %str% %vname%
  196.     setlocal
  197.     set test=%~1_%mod%
  198.     set test=!test:~0,%maxlen%!
  199.     set test=%test:*_=%
  200.     set /a len=maxlen-(%test:#=1+%1)
  201.     endlocal &set %2=%len%
  202.     goto :eof
  203. :cmp %str1% %str2% %vname%
  204.     setlocal
  205.     call :length %1 len_a
  206.     call :length %2 len_b
  207.     if %len_a% gtr %len_b% (endlocal &set %3=1&goto :eof)
  208.     if %len_a% lss %len_b% (endlocal &set %3=-1&goto :eof)
  209.     set str1=%1
  210.     set str2=%2
  211.     if %len_a% equ %len_b% (
  212.         for /l %%n in (0, 1, %len_a%) do (
  213.             if "!str1:~%%n,1!" gtr "!str2:~%%n,1!" (endlocal &set %3=1&goto :eof)
  214.             if "!str1:~%%n,1!" lss "!str2:~%%n,1!" (endlocal &set %3=-1&goto :eof)
  215.         )
  216.         endlocal &set %3=0
  217.     )
  218.     goto :eof
  219. :time_used %time_a% %time_b%
  220.     rem only for few seconds, not consider minutes
  221.     setlocal
  222.     set ta=%1& set tb=%2
  223.     rem insert 1 befeore 00.00 if first num is zero
  224.     set ta=1%ta:~-5%
  225.     set tb=1%tb:~-5%
  226.     set /a dt = %tb:.=% - %ta:.=%
  227.     set dt=%dt:-=%
  228.     set dt=0000%dt%
  229.     set dt=%dt:~-4%
  230.     echo time used: %dt:~0,2%.%dt:~2,2%s
  231.     endlocal
  232.     goto :eof
复制代码
1

评分人数

TOP

本帖最后由 523066680 于 2018-12-23 19:13 编辑

古人云:思而不学则die (die - 通 "殆")
于是我查了 wikipedia ,发现更快的方法,用程序实现起来,比牛顿迭代法更好用(毕竟牛顿迭代法还要涉及大数除法而且每次迭代的精度还不太好判断)。
使用“蛋疼的批处理”粗略实现,精确到小数点后80位,16秒。而且稍微改动就可以支持浮点数开根。



https://en.wikipedia.org/wiki/Methods_of_computing_square_roots

TOP

本帖最后由 523066680 于 2019-1-24 16:31 编辑

回复 19# SQYSQYSQY

就是你这程序有点bug,计算1099511627776的平方根,为啥不一会就退出了
还有我看了半天也不明白你的精确位数在那设置的,每次算到80位就退出了

1. 搜索exit语句,在两处exit /b前面加pause来防止直接退出,不是很难想到吧?
2. 既然已经知道精度是80,完全可以 Ctrl+F 搜索一下 80 定位变量位置



两处 exit 和 80 已经在图中标出

补充:
1. 图中所用的编辑器是Sublime Text 3,可以直接显示运行结果,还能显示运行时间,因此没有加pause。
    这编辑器需要安装插件来支持GBK编码,所以没写中文注释,顺便用翻译软件学一些英语。
2. 我的英语也不好,中学水平
3. 我所知道的代码的BUG是 time_used 函数计算的时间差有问题,不过不打算改了。

TOP

回复 21# SQYSQYSQY

精确到小数点后的是一位一位的。小数点之前的是一次性echo然后退出(:get_int_of_root 函数负责这一块)。
我的电脑,Win7 64位,如果是win8,win10,可能有些微差异吧。

在命令行中调用该脚本看看有没有什么错误提示。

带注释和PAUSE的版本

至于特殊字符的处理,不要浪费时间了,换一种语言,海阔天空。
也许你可以通过各种奇怪的技巧解决这些问题,但在别的语言里,这些都不是问题。
当这个语言运行效率比C低,写起来比C麻烦,写出来的代码还比C难看,为什么不直接用C?
(C可以换成ruby python golang java js lua ... )

Perl 替换方法
  1. use utf8;
  2. use Encode;
  3. my $inp='%&@^"\'?,;<>|\/:() !=';
  4. # 反斜杠因为是剔除而不是替换,用s///处理
  5. $inp=~s/\\//g;
  6. $inp=~tr/%&@^"\'?,;<>|\/:() !=/abcdefghijkl÷÷[]\\mn/;
  7. print encode('gbk', $inp);
复制代码
输出:
abcdefghijkl÷÷[]\mn


换一种玩法,把替换表放在__DATA__字段,这样我就不用手动为某些字符加反斜杠了。第一行是原始数据,第二行、第三行是替换的规则。
  1. my $inp=<DATA>;
  2. my ($from, $to) = <DATA>;
  3. eval "\$inp=~tr/\Q$from\E/\Q$to\E/" or die "$!";
  4. print $inp;
  5. __DATA__
  6. %&@^"'?,;<>|/:() !=\_._\,;=_;=_%_\"=\
  7. %&@^"'?,;<>|/:() !=\_.
  8. abcdefghijklmnopqrst +
复制代码
输出
abcdefghijklmnopqrst + this is a test

TOP

本帖最后由 523066680 于 2018-12-28 21:01 编辑

手算开根的方法,好用

在之前Wikipedia链接的 Decimal (base 10) 一节  Methods_of_computing_square_roots#Decimal_(base_10)
  1. Find the square root of 2.
  2.     1. 4  1  4  2
  3.   _______________
  4. \/ 02.00 00 00 00
  5.    02                  1*1 <= 2 < 2*2                 x = 1
  6.    01                    y = x*x = 1*1 = 1
  7.    01 00               24*4 <= 100 < 25*5             x = 4
  8.    00 96                 y = (20+x)*x = 24*4 = 96
  9.       04 00            281*1 <= 400 < 282*2           x = 1
  10.       02 81              y = (280+x)*x = 281*1 = 281
  11.       01 19 00         2824*4 <= 11900 < 2825*5       x = 4
  12.       01 12 96           y = (2820+x)*x = 2824*4 = 11296
  13.          06 04 00      28282*2 <= 60400 < 28283*3     x = 2
  14.                        The desired precision is achieved:
  15.                        The square root of 2 is about 1.4142
复制代码
一开始还在想为啥用前面的结果*2作为基础 (2 28 282),一计算发现还是那个平方公式展开的结果,这个方法更进一步,又省去了一些计算量,所以速度更快。


补充一些happy886r 的作品,效率极高
批处理大数浮点乘法 - happy886r
批处理大数加法、以及2的1000次方 - happy886r
我拆了一下happy的批处理大数乘法,原来是3位数字为一段,分段计算,效率翻倍,好方法。

其他的一些
批处理怎么算超过15的阶乘?

TOP

回复 20# 523066680

编辑器真漂亮啊,开个新帖介绍介绍吧:)

TOP

返回列表