[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖
下面这个例子既用了乘法又用了除法
应该是符合“分别用正算和反算法”的要求吧:)
楼上的算法难以理解
最多30次的循环
还用二分搜索之类的玩意嘛?
检测溢出可以用大小比较
但是这个不可靠
最可靠的还是先乘再除看是否还是原数
  1. @echo off&setlocal
  2. :loop2
  3. set /p num=请输入大于1的正整数:
  4. echo.
  5. set count=0
  6. set temp=1
  7. :loop
  8. set /a count+=1
  9. set /a temp1=temp
  10. rem 为了避免set/a的对超大的溢出数自动纠错,直接引用原数,并屏蔽可能的错误输出
  11. set /a temp*=%num% 2>nul
  12. set /a temp2=temp/%num% 2>nul
  13. if "%temp1%"=="%temp2%" goto :loop
  14. set /a count-=1
  15. echo %num%的%count%次方接近于cmd的最大值。
  16. echo.
  17. goto :loop2
复制代码
天的白色影子

TOP

程序着实有心意
妙处自不多说
有新人自己体会
只提供几个意见查缺补漏

@echo off&setlocal enabledelayedexpansion 2>nul 3>nul

将 2>nul 3>nul的屏蔽错误用在这里确实有新意
不过别忘了程序执行完还要打扫战场的
否则别人在cmd下执行完后
看不到后续所有命令的错误输出时
都不知道该怪谁

31和2147483648两个常数的指定
有些想当然了
万一别人是在64位的cmd环境下呢?

max+=^!((n-1)>>31)
想来是用来判断n的正负性的
转换为0或1后加入max
但是感觉这用法有些多余
直接取%%a不是很省事吗?
只需要在最后再减个1就可以了
而且用除法的话
n可能会溢出为负值吗?
用乘法的话
也有可能直接溢出到正值

test=1/n+1/(!max!-max)
大概是用来判断n是否为0和max是否溢出的
||goto re是遇到错误时跳转
只是看不明白max
是如果未溢出就要跳转吗?
需要详解一下

另外程序没有对超大数进行处理
即如果用户输入的数直接溢出了该怎么办?
天的白色影子

TOP

书接上回
31和2147483648两个常数是不能随意指定
那么如何在cmd下得到这两个常数值呢?

位数可以通过
set /a _d=<一个超级大数>
然后捕捉并分析其错误输出

最大值可以通过
set __d=<一个超级大数>
set /a _d=__d
1

评分人数

    • zm900612: 第一次看见这种取最大数的方法技术 + 1
天的白色影子

TOP


想通了max的作用和变化了
因为1/n已经判断了n是否为0
所以^!((n-1)>>31)改为^!(n>>31)
只需要判断n是否小于0是可行的
或者将1/n去掉也可以

如果直接取%%a到max
则可以在test中判断n是否小于等于0
set /a max=%%a,"test=1/(^!((n-1)>>31))"

总体来说
是使用set/a的错误抛出
来实现了if的判断跳转

不过正如我在10楼所说
依靠乘方结果的正负性来判断是否溢出是不可靠的
比如100000的乘方结果是1410065408
直接溢出成正值就导致程序判断出错
天的白色影子

TOP

将8楼的代码整理了一下
逻辑上更清晰一些
使可读性更强
并且支持了绝对值大于1的负整数
  1. @echo off&setlocal
  2. :loop2
  3. set /p num=请输入绝对值大于1的整数(可以是负数):
  4. echo.
  5. set count=0
  6. set temp=1
  7. :loop
  8. set /a temp1=temp
  9. rem 为了避免set/a的对超大的溢出数自动纠错,直接引用原数,并屏蔽可能的错误输出
  10. set /a temp*=%num% 2>nul
  11. set /a temp2=temp/%num% 2>nul
  12. rem 如果次方结果乘以整数n再除以整数n不再是原值,则认为乘方结果已接近溢出,跳出
  13. if not "%temp1%"=="%temp2%"                                  goto :jump
  14. if %count% gtr 1024 echo 程序溢出,请确认输入的整数是否正确&pause&goto :eof
  15. set /a count+=1
  16. goto :loop
  17. :jump
  18. echo %num%的%count%次方接近于cmd的最大值。
  19. echo.
  20. goto :loop2
复制代码

[ 本帖最后由 qzwqzw 于 2011-3-14 14:25 编辑 ]
天的白色影子

TOP

没办法台式机网络有点问题,使用手机回复比较累,简短点吧。关于溢出我不多讲,你测试下100000试试,看跟我的代码是否结果一致。
天的白色影子

TOP

请测试你的乘法算法
我这里结果是2
除法算法天生不存在溢出问题我是知道的
天的白色影子

TOP

台式机网络刚恢复
set /a "test=1/(1073741824*n)"||echo %n%的技巧值得借鉴
不过乘法比较消耗CPU
改成“字节与”更好些
set /a "m=1/(n&1)"||echo %n%是偶数
天的白色影子

TOP

标题

没什么可怪异的,计算机的数集就像个圆,一个数不断累加,就像在圆上行走,等加到正数最大值时,就走了个半圆,再走一步就是负数最大值,然后继续延负数轴向前,直到走回零点,就画了一个整圆。然后重新开始,周而复始。类似于道家的阳极生阴,阴极生阳理论。数学上的数集也有类似的特性。溢出为正数不过是在数集圆上走的更远,越过了负数所在的半圆,又回到正数圆而已。不知道这样说你明白了没有?
1

评分人数

    • batman: 很牛的解释,一语惊醒梦中人啊技术 + 1

TOP

抱歉,方程组没看懂
只看到二进制的-1写错了

不知道这样写如何?
二进制    十进制
00...0           0
00...1           1
......
01...1            2147483647
10...0            -2147483648
......
11...1            -1
00...0            0
......
天的白色影子

TOP

嗯,看着理论尤其是数字算式就头大如斗
只看到8位二进制的可表示范围错了(不好意思)
不是"0~128,或者说-64~63"
而是“0~256,或者说-128~127”
天的白色影子

TOP

给出个求极大值的捷径:(此方法通用于所有二进制计算机)
通过二进制逻辑移位来给2开方,一直开到溢出,溢出后其结果是负的,以此负值判断结束条件。
@echo off &setlocal enabledelayedexpansion
for /l %%i in ...
applba 发表于 2011-4-27 09:41


求极值的方法很多
比如11楼的方法
如果非要用二进制移位,也可以这样
@echo off &setlocal enabledelayedexpansion
for /l %%i in  (1,1,256) do (
    set /a "_tmp=1<<%%i"
    if !_tmp! leq 0 (
        set /a "t2=%%i-1"
        set  /a "max=_tmp-1"
        goto 2out
    )
)
:2out
echo 2的!t2!次方最接近极大值!max!
pause>nul
天的白色影子

TOP

思路也很简单,正反一起用,往中间碰撞……
applba 发表于 2011-4-27 10:02

正反同时碰撞的思路不错
可以看考虑修改一下以支持负整数(除-2以外与正整数相同)和超大数(结果是0)
天的白色影子

TOP


请教  第八行和第九行合并(用逗号)表达式后,结果会异常,但是程序运行都正常的……

这个,你去掉set /a 后面的!试试
也就是说不使用变量延迟扩展

超级大数?在cmd.exe是输不进去的,你赋值的时候提示无效……

你是用什么处理输入数的
可以看一下我14楼的代码
它是支持超大数的

关于负数很好弄吧,只看正值就行了, fo ...

没理解你想说的意思
最好能有代码实现让我看看
天的白色影子

TOP

46# caruko
与我8楼代码的思路没有什么本质区别
只是形式上由goto :loop换成了for
这与楼主所说的正算、反算其实不是一回事……
天的白色影子

TOP

返回列表