Board logo

标题: [数值计算] [已解决]批处理怎么找出一组数字中的最小值? [打印本页]

作者: abcdshenji    时间: 2011-5-7 22:35     标题: [已解决]批处理怎么找出一组数字中的最小值?

本帖最后由 abcdshenji 于 2011-5-9 07:58 编辑

今天在网上瞎逛,偶然看到一个“找出一组数字中的最小值”的写法:
  1. @echo off
  2. set/p n=
  3. :p
  4. for /f "tokens=1* delims=." %%i in ("%n%") do set t=#######%%i&call set _%%t:~-8%%=a&if "%%j" neq "" set n=%%j&goto p
  5. for /f "delims==#_" %%i in ('set _') do echo %%i&pause&exit
复制代码
输入:100.50.200.300
输出:50

这段代码真是看的蛋疼。。。有哪位大师能详细解释一下它的思路是怎样的???
作者: CrLf    时间: 2011-5-7 23:05

有更好的算法:
  1. @echo off&setlocal enabledelayedexpansion
  2. set str=123,435,4,43,325,54,234,65,632,45,4342,4265,44,5464
  3. for %%a in (%str%) do (
  4. set /a "n+=^!((%%~a-n)>>31)*(%%~a-n)"
  5. )
  6. echo 最大值:!n!
  7. for %%a in (%str%) do (
  8. set /a "n-=^!((n-%%~a)>>31)*(n-%%~a)"
  9. )
  10. echo 最小值:!n!
  11. pause
复制代码

作者: wankoilz    时间: 2011-5-7 23:05

思路是,在每个数字用#补足8位,将其定义成变量,利用set自动将其排序,最小的排第一。最后用for取第一个就是了
作者: CrLf    时间: 2011-5-7 23:16

换一种更通俗的:
  1. @echo off&setlocal enabledelayedexpansion
  2. set str=123,435,4,43,325,54,234,65,632,45,4342,4265,44,5464
  3. set max=0
  4. for %%a in (%str%) do (
  5.    if %%~a gtr !max! set max=%%~a
  6. )
  7. echo 最大值:!max!
  8. set min=!max!
  9. for %%a in (%str%) do (
  10.    if %%~a lss !min! set min=%%~a
  11. )
  12. echo 最小值:!min!
  13. pause
复制代码

作者: wankoilz    时间: 2011-5-7 23:35

楼上能不能说说你那set/a的奥妙,看起来有点神奇!
作者: abcdshenji    时间: 2011-5-8 01:41

2# zm900612


这个位运算看着不是一般的迷糊,憨豆先生能不能解释一下啊?
作者: abcdshenji    时间: 2011-5-8 01:43

3# wankoilz


set还能排序哦?
作者: abcdshenji    时间: 2011-5-8 01:47

4# zm900612


额。。学C的时候最简单的例子,用到这里了。。
作者: Batcher    时间: 2011-5-8 09:23

7# abcdshenji


能。这是set命令的一个特性:
SET command invoked with just a variable name, no equal sign or value
will display the value of all variables whose prefix matches the name
given to the SET command.  For example:

    SET P

would display all variables that begin with the letter 'P'

作者: CrLf    时间: 2011-5-8 09:56

5# wankoilz


和4楼代码是同一个思路,计算量接近,效率应该差不多,“^!((%%~a-n)>>31)”是判断%%~a(加~是为了严谨)是否小于n,小于则结果为0,否则为1,总之就是模拟判断两数大小的布尔运算,其他的应该很好理解了吧
作者: wankoilz    时间: 2011-5-8 11:07

本帖最后由 wankoilz 于 2011-5-8 11:16 编辑

有意思,最大数是加出来的,最小数是减出来的!
恕我话多,能不能把>>31,和!^的妙用一同说说,先谢过!
作者: CrLf    时间: 2011-5-8 11:30

11# wankoilz

>>是位移,因为bat中正负数的存储方式有别,导致自然数位移超过其二进制形态的位数之后结果为0,而负数则为-1
!是布尔运算,若a为0,则!a为1,若a为1,则!a为0,也可以不要布尔运算,"n-=(1+(%%~a-n)>>31)*(%%~a-n)"意思是一样的,不过!的意图比较明了,易读性更强,至于^虽然本身也是运算符,但是由于此处开启了变量延迟,所以在计算之前还要经过一次预处理,!必须写为^!,而^必须写为^^,另外,若开启变量延迟的代码中要使用!,不光要用^转义,还要用上""
作者: wankoilz    时间: 2011-5-8 13:07

本帖最后由 wankoilz 于 2011-5-8 13:21 编辑

感谢楼上的详细讲解!原来可以用这种方法判断正负,你那set/a构造确实不错!那也可以这样来找最大数:set/a test=1/((%%a-max)>>31) 2>nul || set max=%%a
试了下set/a的另外两个一元运算符 _~ 好像也可以用来判断正负
作者: abcdshenji    时间: 2011-5-8 14:23

本帖最后由 pcl_test 于 2017-3-19 05:53 编辑
  1. set/a test=1/((%%a-max)>>31) 2>nul || set max=%%a
复制代码
2楼和4楼的结合。。。。
作者: abcdshenji    时间: 2011-5-8 14:25

9# Batcher


set 中下划线好像在起作用。。

得好好学习了。。
作者: abcdshenji    时间: 2011-5-8 14:42

9# Batcher


论坛上找不到set排序相关教程啊,,batcher能不能给个链接啊。。。
作者: CrLf    时间: 2011-5-8 16:23

set排序不需要教程...
作者: Batcher    时间: 2011-5-8 16:36

16# abcdshenji


批处理set命令学习笔记
http://bbs.bathome.net/viewthread.php?tid=3774#pid23888
作者: Batcher    时间: 2011-5-8 16:36

15# abcdshenji


你可以把下划线改成其它字符串,比如BatHome
作者: wankoilz    时间: 2011-5-8 19:19

下滑线不是啥特殊字符,只是给变量加的标记,以方便用  set _  罗列出所有 _ 开头的变量。
作者: abcdshenji    时间: 2011-5-9 07:57

20# wankoilz


哦知道了。。谢谢




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