Board logo

标题: 【练习-046】批处理逆转整数二进制位的顺序 [打印本页]

作者: lhjoanna    时间: 2009-4-26 18:15     标题: 【练习-046】批处理逆转整数二进制位的顺序

目的:练习批处理的位操作
要求:1、输入一个整数value,编程实现把value的二进制位模式从左到右变换。
           2、程序不依赖于你的机器上整数的字长,具有可移植性。
举例:输入25,在32位机器上,二进制位:00000000000000000000000000011001,编程使之变成-1744830464,
          二进制为:10011000000000000000000000000000。
加分:完成要求一,加五分;两个都完成,加十分。

[ 本帖最后由 lhjoanna 于 2009-4-26 18:17 编辑 ]
作者: 随风    时间: 2009-4-26 20:42

用位运算来解决,?一点思路都没有...
作者: lhjoanna    时间: 2009-4-26 23:11

呵,就是把整数的二进制位按逆序重排一遍,就是要用到 <<  >>  &   |   这几个运算符了。
作者: batman    时间: 2009-4-27 00:02

先来个非位运算的:
  1. @echo off&setlocal enabledelayedexpansion
  2. set /p var=请输入一个整数:
  3. if %var% lss 0 set "-=a"&set "var=%var:~1%"
  4. for /l %%a in (1,1,32) do (
  5.     if !var! geq 1 (
  6.        set /a yu=var%%2,var/=2
  7.        if defined - set /a yu=1-yu
  8.        set "num=!num!!yu!"
  9.        ) else (
  10.        set "num=!num!0"
  11.     )
  12. )
  13. echo %num%
  14. pause>nul
复制代码

[ 本帖最后由 batman 于 2009-4-27 00:19 编辑 ]
作者: netbenton    时间: 2009-4-27 00:32

  1. @echo off&setlocal enabledelayedexpansion
  2. :lp
  3. (set n=
  4. set o=
  5. set s=
  6. set ns=
  7. echo.
  8. set /p n=输入一个整数:)
  9. (if "%n%"=="" goto :eof
  10. for /l %%a in (1,1,32) do (
  11.         set/a m=n%%2,n=n^>^>1
  12.         set s=!s!!m:~-1!
  13.         set o=!m:~-1!!o!
  14.         set/a ns=^(ns^<^<1^)+m
  15. )
  16. echo 正二进制:!o!   {%n%}
  17. echo 逆转输出:!s!   {!ns!}
  18. goto :lp)
复制代码

[ 本帖最后由 netbenton 于 2009-4-27 00:36 编辑 ]
作者: netbenton    时间: 2009-4-27 01:00

要求二,应该也要定个位数吧,要么64,要么128,
不然,又怎么逆转呢?
作者: lhjoanna    时间: 2009-4-27 01:08

Re:netbenton
这就体现出程序的可移植性了,在你不知道程序将在何种机器上运行的时候,如何能使之适应不同的机器?望兄继续斟酌!
作者: batman    时间: 2009-4-27 01:56

再来,还是非位运算版的:
  1. @echo off&setlocal enabledelayedexpansion
  2. set /a n=1
  3. :lp
  4. set /a n*=2,we+=1
  5. if %n% neq 0 goto lp
  6. set /p var=请输入整数:
  7. if %var% lss 0 set "-=1"&set "var=%var:~1%"
  8. for /l %%a in (1,1,%we%) do (
  9.     if !var! geq 1 (
  10.        set /a yu=var%%2,var/=2
  11.        if defined - set /a yu=1-yu
  12.        set "num=!num!!yu!"
  13.        ) else (
  14.        set "num=!num!0%-%"
  15.     )
  16. )
  17. if defined - call :loop
  18. echo %str%%num%
  19. pause>nul&goto :eof
  20. :loop
  21. set "a=%num:~,1%"
  22. set /a a+=1&if !a! equ 2 set /a a=0
  23. set "str=!a!%str%"&set "num=%num:~1%"
  24. if %a% equ 0 goto loop
复制代码

作者: lhjoanna    时间: 2009-4-27 02:42

在batman的代码中,可移植性体现在事先求得目标机器的位数,这是一种思路,但毕竟影响了程序一定的效率。如何能在尽量不影响程序效率的前提下同时实现两个要求是要考虑的问题。
    提示:采用位操作很高效,在移位的同时隐含机器位数的判断。
作者: pusofalse    时间: 2009-4-27 09:42

发个以前写的,感觉复杂了好多,只是转2进制
  1. @Echo Off
  2. Set /p num=Input:
  3. Call :ToBinary %num% sBinaryString
  4. Echo %sBinaryString%
  5. Pause & Exit /b
  6. :ToBinary numeric, ByRef sBinaryString
  7. SetLocal ENABLEEXTENSIONS
  8. Set "sResult="
  9. Set /a iTopBit = 0, iUnsignedNumber = %~1 "&" 0x7FFFFFFF
  10. If %~1 lss 0 (set /a iTopBit = 1)
  11. If %~1 gtr 0x7fffffff (set /a iTopBit = 1)
  12. :LoopToBinary ###INTERNAL-USED-ONLY###
  13. Set /a iTempNum = iUnsignedNumber "&" 1, iUnsignedNumber ">>=" 1
  14. Set "sResult=%iTempNum%%sResult%"
  15. If %iUnsignedNumber% gtr 0 (goto :LoopToBinary)
  16. EndLocal & Set "%2=%iTopBit%%sResult%" & Exit /b 0
复制代码

[ 本帖最后由 pusofalse 于 2009-4-27 09:49 编辑 ]
作者: lhjoanna    时间: 2009-4-27 10:50

Re:Pusofalse
         兄的代码还可再精简,在正数时输出最好补全后面的0,负数时忘记逆转了吧?
作者: zqz0012005    时间: 2009-4-27 11:17

  1. @echo off
  2. set num=25
  3. set /p "num=Input:\>"
  4. :lp
  5. set /a "bit = num >> n & 1"
  6. set binary=%bit%%binary%
  7. set reverse=%reverse%%bit%
  8. set /a "num2 = num2 << 1 | bit"
  9. set /a "n += 1", "check = 1<<n"
  10. if %check% neq 0 goto lp
  11. echo num : %num%
  12. echo binary : %binary%
  13. echo reverse : %reverse%
  14. echo decimal : %num2%
  15. pause
复制代码
不知道怎样才能不涉及对字长的判断。
作者: lhjoanna    时间: 2009-4-27 11:59

Re:zqz
     呵,兄已经完成了两个要求,此句 if %check% neq 0 goto lp  保证只要%check%不为0就继续循环,这就使循环的次数与机器的字长无关!

[ 本帖最后由 lhjoanna 于 2009-4-27 12:01 编辑 ]
作者: zqz0012005    时间: 2009-4-27 12:13

感觉这样还是与字长有关啊(虽然没有直接使用字长,但还是要判断的)。我是想,如果不考虑写出数字的二进制形式,能不能通过较为简单的方法(不要goto循环),几步就能得出逆转结果。

又觉得,位运算应该必然与字长有关吧。

[ 本帖最后由 zqz0012005 于 2009-4-27 12:15 编辑 ]
作者: lhjoanna    时间: 2009-4-27 12:41

对于具体的某台机器,当然会与字长有关。机器的字长不同,那么逆转后的结果就不同。这也就是采用goto而不是for的原因,这也是兼顾效率与可移植性的方案。
    不知兄所说的不用二进制位几步就可以得出的是什么方法,有什么思路?我觉得位运算已经是几步就可以逆转,当然是要进行循环的。
  1. @echo off
  2. set /p "value=INPUT:"
  3. set /a i=1,answer=0
  4. :begin
  5. set /a "answer<<=1,b=value&1"
  6. set /a "answer|=b,value>>=1,i<<=1"&set "binary=%binary%%b%"
  7. if %i% neq 0 goto begin
  8. echo Decimal:%answer% &echo Binary :%binary%
  9. pause>nul
复制代码

作者: netbenton    时间: 2009-4-27 12:53

@echo off&setlocal enabledelayedexpansion
set len=1&for /l %%a in (1,1,256) do (set/a len=len^<^<1,1/len 2>nul || (set len=%%a&goto :lp))
set len=512&rem 首先测出字长,应该达不到512位吧?
:lp
(set n=
set o=
set s=
set ns=
echo.
set /p n=输入一个整数:)
(if "%n%"=="" goto :eof
for /l %%a in (1,1,!len!) do (
        set/a m=n%%2,n=n^>^>1
        set s=!s!!m:~-1!
        set o=!m:~-1!!o!
        set/a ns=^(ns^<^<1^)+m
)
echo 正二进制:!o!   {%n%}
echo 逆转输出:!s!   {!ns!}
goto :lp)
作者: lhjoanna    时间: 2009-4-27 13:05

Re:netbenton
        我想正确的思路是不能留下隐患,至于有没有512的我不清楚,但计算机是不断发展的,也要考虑程序能适应以后的发展。当然在效率要求不是太严格或如需改变但代码变动不大的情况下也可以。
    还有个小问题,就是兄的代码在输入负数的情况下,逆转后的十进制数的正负存在点儿小问题。
作者: netbenton    时间: 2009-4-27 19:46     标题: re 楼主

已经解决通用和符号问题
  1. @echo off&setlocal enabledelayedexpansion
  2. set/a len=1,n=1
  3. :rep
  4. set/a len=len+len,n=n^<^<len,1/n 2>nul&&goto :rep
  5. :lp
  6. (set n=
  7. set o=
  8. set s=
  9. set ns=
  10. echo.
  11. set /p n=输入一个整数:)
  12. (if "%n%"=="" goto :eof
  13. for /l %%a in (1,1,!len!) do (
  14. set/a m=n%%2,n=n^>^>1,m*=m
  15. set s=!s!!m!
  16. set o=!m!!o!
  17. set/a ns=^(ns^<^<1^)+m
  18. )
  19. echo 正二进制:!o!   {%n%}
  20. echo 逆转输出:!s!   {!ns!}
  21. goto :lp)
复制代码
真的还可以精简,把一些地方换成了按位运算,更快更简
但初始化还是保持用set,反正只有四行,按字数来算还更少一点。
  1. @echo off&setlocal enabledelayedexpansion
  2. set/a len=1,n=1
  3. :rep
  4. set/a "len<<=1,n<<=len,1/n" 2>nul&&goto :rep
  5. :lp
  6. set n=&set o=&set s=&set ns=&echo.&set /p n=输入一个整数:
  7. (if "%n%"=="" goto :eof
  8. for /l %%a in (1,1,%len%) do (
  9. set/a "m=n&1,n>>=1,ns=ns<<1|m"
  10. set s=!s!!m!
  11. set o=!m!!o!
  12. )
  13. echo 正二进制:!o!   {%n%}
  14. echo 逆转输出:!s!   {!ns!}
  15. goto :lp)
复制代码

[ 本帖最后由 netbenton 于 2009-4-27 22:44 编辑 ]
作者: lhjoanna    时间: 2009-4-27 20:12

Re:netbenton
         执行结果,要求都正确,代码还有几处可以精简的地方。进入循环刚开始的四个变量清空操作可以在循环首尾用一对setlocal enabledelayedexpansion和endlocal代替。还有可移植性的另一种思路在12楼与15楼都有体现!
作者: lhjoanna    时间: 2009-4-28 17:49

今天忽然想到了用递归来算,代码以32位为例,效率也没有纯位运算高,仅作研究。
  1. @echo off
  2. set /p "value=INPUT:"
  3. set /a "i=1<<31",flag=1
  4. call :loop %i%
  5. pause>nul&goto :eof
  6. :loop
  7. set /a "i=%1,n=i&value,i>>=1,n=!(!n)"
  8. if %flag% equ 1 set /a i="1<<30" &set flag=0
  9. if %i% neq 0 (call :loop %i% %n%) else <nul set /p=%n%
  10. <nul set /p=%2
复制代码

作者: terse    时间: 2009-5-1 11:20

以前写的2进制转换的  改下 不知通否
  1. @echo off&setlocal enabledelayedexpansion
  2. set/p a=INPUT:
  3. set i=1
  4. for /l %%i in (31,-1,0) do (
  5.     set/a n=^!^(^!^(a%%2^)^)2>nul
  6.     set/a i*=n"<<"%%i,d+=i,i=1
  7.     set b=!b!!n!
  8.     if !a! geq 2 (set/a a/=2)else set a=0
  9.   )
  10. echo Decimal:%d% &echo Binary :%b%
  11. pause
复制代码

作者: lhjoanna    时间: 2009-5-1 11:54

兄的代码在负数情况有些小问题
作者: terse    时间: 2009-5-1 13:24

原帖由 lhjoanna 于 2009-5-1 11:54 发表
兄的代码在负数情况有些小问题

是的  有问题  这样呢
  1. @echo off&setlocal enabledelayedexpansion
  2. set/p a=INPUT:
  3. for /l %%i in (31,-1,0) do (
  4.     set/a "n=a&1,a>>=1,d+=n<<%%i"
  5.     set b=!b!!n!
  6.   )
  7. echo Decimal:%d% &echo Binary :%b%
  8. pause
复制代码





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