Board logo

标题: [数值计算] 看起来正常计算的两个数,批处理结果怎么变成了负数? [打印本页]

作者: zds612    时间: 2018-10-30 14:05     标题: 看起来正常计算的两个数,批处理结果怎么变成了负数?

各位,我写了个用于监视磁盘容量的小代码,刚开始测试还正常,多试几次之后就异常了

现象是,在xp下,通过dir+for获取到磁盘剩余字节,除以1048576(转为MB单位)

结果为负数了。。如图:


在win7环境下,计算结果为0,提示:无效数字,无效数字。数字精确度限为 32 位。

如图:

请大家帮忙看看是什么问题,谢谢!

贴代码:
  1. @echo off
  2. mode con cols=50 lines=10
  3. color 0a
  4. Title -[磁盘检测程序(自动电邮告警)]
  5. set log_file_name=RunLog.txt
  6. set lineno_max=365
  7. set avail=1000
  8. set svrname="测试服务器"
  9. set ipaddr="192.168.180.000"
  10. set freesize=0
  11. set num=1048576
  12. set disk1=c
  13. if NOT exist %log_file_name% (echo 执行日志:>%log_file_name%)
  14. for /f "delims=:" %%a in ('findstr/n .* "%log_file_name%"') do set lineno=%%a
  15. echo %log_file_name%文件共有%lineno%行
  16. if %lineno% GTR %lineno_max% (echo 执行日志:>%log_file_name% && echo %log_file_name%文件已经清空!)
  17. for /f "tokens=3 delims= " %%a in ('dir /-c %disk1%:') do set "mc=%%a"
  18. echo %mc%字节
  19. set /a "freesize=%mc%/1000"
  20. echo %disk1%盘剩余空间为%freesize%MB
  21. echo 警戒值为%avail%MB
  22. if %freesize% LSS %avail% (goto xiaoyu) else (goto exit)
  23. :xiaoyu
  24. echo %disk1%盘空间不足%avail%MB,将电邮告警!
  25. echo 发电邮告警....(此功能由CmdMail实现,此处仅作演示说明。)
  26. ping -n 4 127.1>nul
  27. pause&&exit
  28. :exit
  29. echo 空间充裕,程序退出。&& echo %date% %time%:执行本程序,%disk1%盘磁盘空间%freesize%MB,未达到警戒值%avail%MB;>>%log_file_name%
  30. ping -n 4 127.1>nul
  31. exit
复制代码

作者: hnfeng    时间: 2018-10-30 14:51

会不会是超过了CMD可处理的最大数字了

BTW:你的颜色搭配太刺眼了吧
作者: Batcher    时间: 2018-10-30 14:55

BAT能够直接计算的数值大小非常有限,不适合用来判断磁盘空间,推荐使用PowerShell
http://bbs.bathome.net/thread-26200-1-1.html
作者: hnfeng    时间: 2018-10-30 15:27

或者使用第三方工具来计算
例如  http://bbs.bathome.net/thread-15369-1-2.html

不懂 powershell ,老了,学不动了
作者: yhcfsr    时间: 2018-10-30 18:05

32位的无符号整形最大值是2^32-1也就是4G,超过这个数字就会溢出.
非要用BAT的话,就采用BAT+JS或BAT+VBS的方式处理
作者: zds612    时间: 2018-10-31 15:05

回复 2# hnfeng


    呵呵,可能我视力不好,感觉这样才看得清楚
作者: zds612    时间: 2018-10-31 15:06

回复 3# Batcher


    看了看powershell,感觉很厉害很好用,但是batch都搞得我一头雾水,还是想想别的办法

    感谢帮忙!
作者: zds612    时间: 2018-10-31 15:07

回复 4# hnfeng


    非常感谢,我去研究研究,希望不会太难
作者: zds612    时间: 2018-10-31 15:08

回复 5# yhcfsr


    vbs是个好办法,但我只会用来弹提示框,上面有个朋友提供了一个工具,我去看看,谢谢你!
作者: zds612    时间: 2018-10-31 15:11

回复 4# hnfeng


    原帖里的链接失效了,你有保存附件吗?求分享:zds612@163.com
作者: Batcher    时间: 2018-10-31 16:06

回复 7# zds612


试试这个能看懂吗:批处理实现大数字加减乘除
http://bbs.bathome.net/thread-3372-1-1.html
作者: hnfeng    时间: 2018-11-1 09:13

回复 10# zds612

前面说的那个较大,传不上来。给你个更小的吧
  1. C:\temp>set abc=1000000000000000000000
  2. C:\temp>ClCalc.exe %abc%/1000/1000/1000/1000/1000/1000
  3. 1000000000000000000000/1000/1000/1000/1000/1000/1000 = 1000
  4. C:\temp>ClCalc.exe %abc%/1024/1024/1024/1024/1024/1024
  5. 1000000000000000000000/1024/1024/1024/1024/1024/1024 = 867.361737988404
复制代码
没验证。你自己先验证这个计算结果是否准确
作者: zds612    时间: 2018-11-1 09:25

本帖最后由 zds612 于 2018-11-1 09:26 编辑

回复 11# Batcher


    感谢大大的帮忙,对我很有帮助,已经可以正常计算了

    但是出现另一个问题,不管警戒值设为多大,结果都是空间充裕

    问题1:感觉好像我那个比较的if语句没有什么作用,能劳烦帮我看看嘛?

    问题2:批处理中带小数的数字如何取整?
  1. @echo off
  2. mode con cols=50 lines=10
  3. color 0a
  4. Title -[磁盘检测程序(自动电邮告警)]
  5. set log_file_name=RunLog.txt
  6. set lineno_max=365
  7. set avail=100000
  8. set svrname="测试服务器"
  9. set ipaddr="132.147.180.000"
  10. set freesize=0
  11. set num=1048576
  12. set disk1=c
  13. if NOT exist %log_file_name% (echo 执行日志:>%log_file_name%)
  14. for /f "delims=:" %%a in ('findstr/n .* "%log_file_name%"') do set lineno=%%a
  15. echo %log_file_name%文件共有%lineno%行
  16. if %lineno% GTR %lineno_max% (echo 执行日志:>%log_file_name% && echo %log_file_name%文件已经清空!)
  17. for /f "tokens=3 delims= " %%a in ('dir /-c %disk1%:') do set "mc=%%a"
  18. echo %mc%字节
  19. set suru=%mc%/%num%
  20. call :cu0  %suru:/= % freesize
  21. echo %disk1%盘剩余空间为%freesize%MB
  22. echo 警戒值为%avail%MB
  23. if %freesize% LSS %avail% (goto xiaoyu) else (goto exit)
  24. :xiaoyu
  25. echo %disk1%盘空间不足%avail%MB,将电邮告警!
  26. echo 发电邮告警....(此功能由CmdMail实现,此处仅作演示说明。)
  27. ping -n 4 127.1>nul
  28. pause&&exit
  29. :exit
  30. echo 空间充裕,程序退出。&& echo %date% %time%:执行本程序,%disk1%盘磁盘空间%freesize%MB,未达到警戒值%avail%MB;>>%log_file_name%
  31. ping -n 4 127.1>nul
  32. pause&&exit
  33. :cu0 500位内整数除法函数(封装)by @随风 bbs.bathome.net
  34. ::函数内有 cu1 cu2 cu3 cu4 四个标签,引用时需注意
  35. setlocal enabledelayedexpansion&set "lin=00000"
  36. set /a zongw=1000,cs1w=0,cs2w=0,falg=0,x=0
  37. if "!str!"=="1" Endlocal&set %~3=%ff%!num!&goto :EOF
  38. if "%~1"=="0" set sang=0&goto cu4
  39. if "!str!"=="0" set sang=以零为除数的错误。&goto cu4
  40. if not defined xiaosu set /a xiaosu=10
  41. for /l %%a in (1 1 5) do set "lin=!lin!!lin!!lin!"
  42. set sang=&set ppp=&set var1=%~1&set "var2=%~2"
  43. for /f "tokens=* delims=0" %%a in ("!var1!")do set var1=%%a
  44. for /f "tokens=* delims=0" %%a in ("!var2!")do set var2=%%a
  45. for /l %%a in (0 1 9)do (set "var1=!var1:%%a= %%a !"
  46. set "var2=!var2:%%a= %%a !")
  47. for %%a in (!var1!) do set /a cs1w+=1
  48. for %%a in (!var2!) do set /a cs2w+=1
  49. for /l %%a in (1 1 10) do (set t=&set cs=%~2&set/a j=0
  50. for /l %%b in (1 1 !cs2w!) do (set /a a=%%a*!cs:~-1!+j
  51. set t=!a:~-1!!t!&set a=0!a!&set "j=!a:~-2,1!"
  52. set cs=!cs:~0,-1!&set cs%%a=&set "bj%%a=")
  53. if !j! neq 0 (set cs%%a=!lin!!j!!t!&set "bj%%a=!j!!t!"
  54. ) else set cs%%a=!lin!!t!&set "bj%%a=!t!"
  55. set "cs%%a=!cs%%a:~-%zongw%!")
  56. set var2=!lin!!var2: =!&set "var2=!var2:~-%zongw%!"
  57. set /a cswc=cs1w-cs2w&set "var1=!var1: =!"
  58. if !cswc! lss 0 (set cswc=!cswc:-=!&set/a flag=1
  59. for /l %%a in (1 1 !cswc!)do (
  60. if %%a leq 11 set sang=0!sang!&set /a x=cswc-1
  61. set "var1=!var1!0")
  62. set "sang=!sang:~0,1!.!sang:~1!")
  63. set ppp=!var1:~0,%cs2w%!&set "var1=!var1:~%cs2w%!"
  64. if !flag! equ 1 (set /a bul=1) else set /a bul=0
  65. goto cu2
  66. :cu1
  67. if not defined var1 (set "var1=0"
  68. if not defined ppp goto cu4
  69. if !flag! equ 0 (set sang=!sang!.&set /a flag=1))
  70. set/a bul=1&set ppp=!ppp!!var1:~0,1!&set "var1=!var1:~1!"
  71. :cu2
  72. if !x! geq %xiaosu% goto cu4
  73. set pvar1=!lin!!ppp!&set "pvar1=!pvar1:~-%zongw%!"
  74. if "!pvar1!" lss "!var2!" (
  75. if !bul! equ 1 (set sang=!sang!0&set /a bul=0
  76. if !flag! equ 1 set /a x+=1)
  77. if "!ppp:~0,1!"=="0" set "ppp="
  78. goto cu1)
  79. if !flag! equ 1 set /a x+=1
  80. set /a bul=0
  81. ::计算商
  82. for /l %%a in (1 1 10) do (
  83. if "!cs%%a!" equ "!pvar1!" (
  84. set "sang=!sang!%%a"&set "yu=!bj%%a!"&goto cu3)
  85. if "!cs%%a!" gtr "!pvar1!" (set /a s=%%a-1
  86. set "sang=!sang!!s!"&set yu=!t!&goto cu3)
  87. set "t=!bj%%a!")
  88. :cu3 计算差
  89. set cjs=!ppp!&set cj1=&set m=&set/a jjj=0
  90. for /l %%a in (0 1 9) do set "cjs=!cjs:%%a= %%a !"
  91. for %%a in (!cjs!) do set "cj1=%%a !cj1!"
  92. for %%a in (!cj1!) do (if "!yu!"=="" set/a yu=0
  93. set /a a=%%a-jjj,b=!yu:~-1!
  94. if !a! lss !b! (set /a a+=10,jjj=1)else set/a jjj=0
  95. set /a w=a-b&set m=!w!!m!&set yu=!yu:~0,-1!)
  96. for /f "tokens=* delims=0" %%m in ("!m!") do (
  97. if "%%m"=="" (set m=0) else set "m=%%m")
  98. if !m! equ 0 (
  99. if "!var1:0=!"=="" set sang=!sang!!var1!&goto cu4
  100. set ppp=&goto cu1) else set "ppp=!m!"
  101. goto cu2
  102. :cu4
  103. if "!sang:~0,1!"=="." set "sang=0!sang!"
  104. Endlocal&set %~3=%ff%%sang%&goto :EOF
复制代码

作者: zds612    时间: 2018-11-1 09:32

回复 12# hnfeng


    非常感谢,可以格式化输出吗?

    只输出结果,不要等式?帮助信息里面好像没有提到参数(英文烂。。。)

    谢谢你!
作者: hnfeng    时间: 2018-11-1 09:40

回复 6# zds612


    我喜欢 color 3e
作者: Batcher    时间: 2018-11-1 10:06

http://bcn.bathome.net/s/tool/index.html?key=计算
这里有好几个命令行工具,可以试试。
作者: zds612    时间: 2018-11-1 13:25

回复 16# Batcher


    是的,我也在里面找了几个,其中一个expr.exe可以实现需求
  1. D:\bat_test>expr.exe 50 / 25
  2. 2
复制代码
但是我不会如何将计算结果赋值给变量,能否指导一下?谢谢!
作者: Batcher    时间: 2018-11-1 14:04

回复 17# zds612


    放在 for /f 命令里面就行了,类似顶楼代码第15行。
作者: WHY    时间: 2018-11-1 21:30

本帖最后由 WHY 于 2018-11-3 16:02 编辑

个人认为,楼主无非是想判断磁盘剩余空间是否超过警戒值,没有必要转换成MB,补零就行了。
假设警戒值为 1GB
  1. @echo off
  2. set "alarmValue=1073741824"
  3. for /f "tokens=3" %%i in ('dir /a /-c C:') do set "freeSpace=%%i"
  4. set "s1=00000000000000000000%freeSpace%"
  5. set "s2=00000000000000000000%alarmValue%"
  6. if "%s1:~-20%" LSS "%s2:~-20%" (
  7.     echo;低于警戒值,发邮件
  8. ) else (
  9.     echo;空间充足,剩余%freeSpace%字节,警戒值%alarmValue%字节
  10. )
  11. pause
复制代码

作者: WHY    时间: 2018-11-1 21:34

本帖最后由 WHY 于 2018-11-3 16:03 编辑

一定要转换为MB,这样应该可以:
  1. @echo off & setlocal enabledelayedexpansion
  2. set "alarmValue=1024"
  3. for /f "tokens=3" %%i in ('dir /a /-c C:') do set "freeSpace=%%i"
  4. call :GetMB
  5. if !rt! LSS !alarmValue! (
  6.     echo;低于警戒值,发邮件
  7. ) else (
  8.     echo;空间充足,剩余!rt!MB,警戒值!alarmValue!MB
  9. )
  10. pause & exit /b
  11. :GetMB
  12. set "str=!freeSpace!FEDCBA9876543210" & set /a Len=0x!str:~16,1!
  13. for /L %%i in (0 1 !Len!) do (
  14.         set "sang=!yu!!freeSpace:~%%i,1!"
  15.         set /a yu=sang%%1048576,sang/=1048576
  16.         if "!yu!" == "0" set "yu="
  17.         set "rt=!rt!!sang!"
  18. )
  19. for /f "tokens=* delims=0" %%i in ("!rt!") do set /a rt=%%i+0
复制代码





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