📄 mathc.html
字号:
17 v4=171.63 18 19 var2=$(bc << EOF 20 scale = 4 21 a = ( $v1 + $v2 ) 22 b = ( $v3 * $v4 ) 23 a * b + 15.35 24 EOF 25 ) 26 echo $var2 # 593487.8452 27 28 29 var3=$(bc -l << EOF 30 scale = 9 31 s ( 1.7 ) 32 EOF 33 ) 34 # 返回弧度为1.7的正弦. 35 # "-l"选项将会调用'bc'算数库. 36 echo $var3 # .991664810 37 38 39 # 现在, 在函数中试一下... 40 hyp= # 声明全局变量. 41 hypotenuse () # 计算直角三角形的斜边. 42 { 43 hyp=$(bc -l << EOF 44 scale = 9 45 sqrt ( $1 * $1 + $2 * $2 ) 46 EOF 47 ) 48 # 不幸的是, 不能从bash函数中返回浮点值. 49 } 50 51 hypotenuse 3.68 7.31 52 echo "hypotenuse = $hyp" # 8.184039344 53 54 55 exit 0</PRE></FONT></TD></TR></TABLE><HR></DIV><DIVCLASS="EXAMPLE"><HR><ANAME="CANNON"></A><P><B>例子 12-45. 计算圆周率</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 # cannon.sh: Approximating PI by firing cannonballs. 3 4 # 这事实上是一个"Monte Carlo"蒙特卡洛模拟的非常简单的实例: 5 #+ 蒙特卡洛模拟是一种由现实事件抽象出来的数学模型, 6 #+ 由于要使用随机抽样统计来估算数学函数, 所以使用伪随机数来模拟真正的随机数. 7 8 # 想象有一个完美的正方形土地, 边长为10000个单位. 9 # 在这块土地的中间有一个完美的圆形湖, 10 #+ 这个湖的直径是10000个单位. 11 # 这块土地的绝大多数面积都是水, 当然只有4个角上有一些土地. 12 # (可以把这个湖想象成为这个正方形的内接圆.) 13 # 14 # 我们将使用老式的大炮和铁炮弹 15 #+ 向这块正方形的土地上开炮. 16 # 所有的炮弹都会击中这块正方形土地的某个地方. 17 #+ 或者是打到湖上, 或者是打到4个角的土地上. 18 # 因为这个湖占据了这个区域大部分地方, 19 #+ 所以大部分的炮弹都会"扑通"一声落到水里. 20 # 而只有很少的炮弹会"砰"的一声落到4个 21 #+ 角的土地上. 22 # 23 # 如果我们发出的炮弹足够随机的落到这块正方形区域中的话, 24 #+ 那么落到水里的炮弹与打出炮弹总数的比率, 25 #+ 大概非常接近于PI/4. 26 # 27 # 原因是所有的炮弹事实上都 28 #+ 打在了这个土地的右上角, 29 #+ 也就是, 笛卡尔坐标系的第一象限. 30 # (之前的解释只是一个简化.) 31 # 32 # 理论上来说, 如果打出的炮弹越多, 就越接近这个数字. 33 # 然而, 对于shell 脚本来说一定会做些让步的, 34 #+ 因为它肯定不能和那些内建就支持浮点运算的编译语言相比. 35 # 当然就会降低精度. 36 37 38 DIMENSION=10000 # 这块土地的边长. 39 # 这也是所产生随机整数的上限. 40 41 MAXSHOTS=1000 # 开炮次数. 42 # 10000或更多次的话, 效果应该更好, 但有点太浪费时间了. 43 PMULTIPLIER=4.0 # 接近于PI的比例因子. 44 45 get_random () 46 { 47 SEED=$(head -1 /dev/urandom | od -N 1 | awk '{ print $2 }') 48 RANDOM=$SEED # 来自于"seeding-random.sh" 49 #+ 的例子脚本. 50 let "rnum = $RANDOM % $DIMENSION" # 范围小于10000. 51 echo $rnum 52 } 53 54 distance= # 声明全局变量. 55 hypotenuse () # 从"alt-bc.sh"例子来的, 56 { # 计算直角三角形的斜边的函数. 57 distance=$(bc -l << EOF 58 scale = 0 59 sqrt ( $1 * $1 + $2 * $2 ) 60 EOF 61 ) 62 # 设置 "scale" 为 0 , 好让结果四舍五入为整数值, 63 #+ 这也是这个脚本中必须折中的一个地方. 64 # 不幸的是, 这将降低模拟的精度. 65 } 66 67 68 # main() { 69 70 # 初始化变量. 71 shots=0 72 splashes=0 73 thuds=0 74 Pi=0 75 76 while [ "$shots" -lt "$MAXSHOTS" ] # 主循环. 77 do 78 79 xCoord=$(get_random) # 取得随机的 X 与 Y 坐标. 80 yCoord=$(get_random) 81 hypotenuse $xCoord $yCoord # 直角三角形斜边 = 82 #+ distance. 83 ((shots++)) 84 85 printf "#%4d " $shots 86 printf "Xc = %4d " $xCoord 87 printf "Yc = %4d " $yCoord 88 printf "Distance = %5d " $distance # 到湖中心的 89 #+ 距离 -- 90 # 起始坐标点 -- 91 #+ (0,0). 92 93 if [ "$distance" -le "$DIMENSION" ] 94 then 95 echo -n "SPLASH! " 96 ((splashes++)) 97 else 98 echo -n "THUD! " 99 ((thuds++))100 fi101 102 Pi=$(echo "scale=9; $PMULTIPLIER*$splashes/$shots" | bc)103 # 将比例乘以4.0.104 echo -n "PI ~ $Pi"105 echo106 107 done108 109 echo110 echo "After $shots shots, PI looks like approximately $Pi."111 # 如果不太准的话, 那么就提高一下运行的次数. . .112 # 可能是由于运行错误和随机数随机程度不高造成的.113 echo114 115 # }116 117 exit 0118 119 # 要想知道一个shell脚本到底适不适合对计算应用进行模拟的话?120 #+ (一种需要对复杂度和精度都有要求的计算应用).121 #122 # 一般至少需要两个判断条件.123 # 1) 作为一种概念的验证: 来显示它可以做到. 124 # 2) 在使用真正的编译语言来实现一个算法之前, 125 #+ 使用脚本来测试和验证这个算法. </PRE></FONT></TD></TR></TABLE><HR></DIV></DD><DT><ANAME="DCREF"></A><BCLASS="COMMAND">dc</B></DT><DD><P><BCLASS="COMMAND">dc</B>(桌面计算器<BCLASS="COMMAND">d</B>esk <BCLASS="COMMAND">c</B>alculator)工具是面向栈的, 并且使用RPN(逆波兰表达式<SPANCLASS="QUOTE">"Reverse Polish Notation"</SPAN>又叫<SPANCLASS="QUOTE">"后缀表达式"</SPAN>). 与<BCLASS="COMMAND">bc</B>命令很相似, 但是这个工具具备好多只有编程语言才具备的能力. </P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 ( 2 译者注: 正常表达式 逆波兰表达式 3 a+b a,b,+ 4 a+(b-c) a,b,c,-,+ 5 a+(b-c)*d a,d,b,c,-,*,+ 6 ) 7 </PRE></FONT></TD></TR></TABLE><P>绝大多数人都避免使用这个工具, 因为它需要非直观的RPN输入, 但是, 它却有特定的用途. </P><DIVCLASS="EXAMPLE"><HR><ANAME="HEXCONVERT"></A><P><B>例子 12-46. 将10进制数字转换为16进制数字</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 # hexconvert.sh: 将10进制数字转换为16进制数字. 3 4 E_NOARGS=65 # 缺少命令行参数错误. 5 BASE=16 # 16进制. 6 7 if [ -z "$1" ] 8 then 9 echo "Usage: $0 number" 10 exit $E_NOARGS 11 # 需要一个命令行参数. 12 fi 13 # 练习: 添加命令行参数检查. 14 15 16 hexcvt () 17 { 18 if [ -z "$1" ] 19 then 20 echo 0 21 return # 如果没有参数传递到这个函数中的话就"return" 0. 22 fi 23 24 echo ""$1" "$BASE" o p" | dc 25 # "o" 设置输出的基数(数制). 26 # "p" 打印栈顶. 27 # 参考dc的man页来了解其他的选项. 28 return 29 } 30 31 hexcvt "$1" 32 33 exit 0</PRE></FONT></TD></TR></TABLE><HR></DIV><P>通过仔细学习<BCLASS="COMMAND">dc</B>的<ICLASS="FIRSTTERM">info</I>页, 可以更深入的理解这个复杂的命令. 但是, 有一些精通<EM>dc巫术</EM>小组经常会炫耀他们使用这个强大而又晦涩难懂的工具时的一些技巧, 并以此为乐. </P><P> <TABLEBORDER="1"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="SCREEN"><SAMPCLASS="PROMPT">bash$ </SAMP><KBDCLASS="USERINPUT">echo "16i[q]sa[ln0=aln100%Pln100/snlbx]sbA0D68736142snlbxq" | dc"</KBD><SAMPCLASS="COMPUTEROUTPUT">Bash</SAMP> </PRE></FONT></TD></TR></TABLE> </P><DIVCLASS="EXAMPLE"><HR><ANAME="FACTR"></A><P><B>例子 12-47. 因子分解</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 # factr.sh: 分解约数 3 4 MIN=2 # 如果比这个数小就不行了. 5 E_NOARGS=65 6 E_TOOSMALL=66 7 8 if [ -z $1 ] 9 then 10 echo "Usage: $0 number" 11 exit $E_NOARGS 12 fi 13 14 if [ "$1" -lt "$MIN" ] 15 then 16 echo "Number to factor must be $MIN or greater." 17 exit $E_TOOSMALL 18 fi 19 20 # 练习: 添加类型检查(防止非整型的参数). 21 22 echo "Factors of $1:" 23 # --------------------------------------------------------------------------------- 24 echo "$1[p]s2[lip/dli%0=1dvsr]s12sid2%0=13sidvsr[dli%0=1lrli2+dsi!>.]ds.xd1<2" | dc 25 # --------------------------------------------------------------------------------- 26 # 上边这行代码是Michel Charpentier编写的<charpov@cs.unh.edu>. 27 # 在此使用经过授权(感谢). 28 29 exit 0</PRE></FONT></TD></TR></TABLE><HR></DIV></DD><DT><ANAME="AWKMATH"></A><BCLASS="COMMAND">awk</B></DT><DD><P>在脚本中使用浮点运算的另一种方法是使用<AHREF="awk.html#AWKREF">awk</A>内建的数学运算函数, 可以用在<AHREF="wrapper.html#SHWRAPPER">shell包装</A>中. </P><DIVCLASS="EXAMPLE"><HR><ANAME="HYPOT"></A><P><B>例子 12-48. 计算直角三角形的斜边</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 # hypotenuse.sh: 返回直角三角形的斜边. 3 # (直角边长的平方和,然后对和取平方根) 4 5 ARGS=2 # 需要将2个直角边作为参数传递进来. 6 E_BADARGS=65 # 错误的参数值. 7 8 if [ $# -ne "$ARGS" ] # 测试传递到脚本中的参数值. 9 then 10 echo "Usage: `basename $0` side_1 side_2" 11 exit $E_BADARGS 12 fi 13 14 15 AWKSCRIPT=' { printf( "%3.7f\n", sqrt($1*$1 + $2*$2) ) } ' 16 # 命令 / 传递给awk的参数 17 18 19 # 现在, 将参数通过管道传递给awk. 20 echo -n "Hypotenuse of $1 and $2 = " 21 echo $1 $2 | awk "$AWKSCRIPT" 22 23 exit 0</PRE></FONT></TD></TR></TABLE><HR></DIV></DD></DL></DIV></DIV><DIVCLASS="NAVFOOTER"><HRALIGN="LEFT"WIDTH="100%"><TABLESUMMARY="Footer navigation table"WIDTH="100%"BORDER="0"CELLPADDING="0"CELLSPACING="0"><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top"><AHREF="terminalccmds.html"ACCESSKEY="P">前一页</A></TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><AHREF="index.html"ACCESSKEY="H">首页</A></TD><TDWIDTH="33%"ALIGN="right"VALIGN="top"><AHREF="extmisc.html"ACCESSKEY="N">下一页</A></TD></TR><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top">终端控制命令</TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><AHREF="external.html"ACCESSKEY="U">上一级</A></TD><TDWIDTH="33%"ALIGN="right"VALIGN="top">混杂命令</TD></TR></TABLE></DIV></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -