1、完整版)vb常用算法介绍 一、累加算法 如果在设计过程中遇到求1+2+3+……+100等连加问题时,就可以用累加算法来解决。 累加算法的一般做法是设一个变量 s,作为累加器使用,初值为0,设一个变量用来保存加数。一般在累加算法中的加数都是有规律可循,可结合循环程序来实现. 一个循环程序的设计,如果以下三方面确定下来:变量的赋初值、循环体的内容、循环结束条件,那么根据循环语句的格式,就很容易写出相应的循环程序。 例:求1+2+3++100的累加和,并打印输出 分析: 设累加器S,初值为0,加数用变量I表示 当I=1时,累加器S= S+I = 0+
2、1=1 当I=2时,累加器S= S+I =1+2= 3 当I=3时,累加器S=S+I =3+3 =6 当I=4时,累加器S=S+I =6+4 =10 …… 当I=100时,累加器S=S+100=1+2+3+……+99+100=5050 不难看出,I的值从1变化到100的过程中,累加器均执行同一个操作:S=S+I,S=S+I的操作执行了100次,所以该程序段可写成: Dim I As Integer, S As Integer S = 0 ‘给累加器s赋初值 For S = 1 To 100 S= S + I ‘I
3、既作为循环变量,又作为加数 Next I Print "1+2+……100=”; S 考虑一下:语句Print ”1+2+……100=”; S可以放在循环体中吗? 延伸一下: 上述算法对数值型数据,执行的是累加操作,如果对字符串型数据,完成的是字符串的连接. 例:从键盘上输入一串字符,要求将其加密后显示在文本框Text1中,加密的方法是将每一个字符转变为它的后一位字符,如:A转变为B,1转变为2。 分析: 因为涉及对每一个字符做相应处理再连接成一个新串,所以可以用类似累加的算法。定义一个变量str1用来接收输入的原始字符串,变量str2用来接收加密后的字符串,初值为
4、空串。可用Len()函数得出字符串的长度,用循环控制,从左向右逐个取字符,截取字符的功能可用函数Mid()完成,由于要做加密操作,可利用Asc()函数获得字符的Ascii码,用Chr()函数获得Ascii码对应的字符。 程序段如下: Dim str1 As String, ch As String * 1 Dim i As Integer, str2 As String str1 = InputBox(”输入原始字符串:”) For i = 1 To Len(str1) str2 = str2 + Chr(Asc(Mid(str1, i, 1)) + 1) ‘将加
5、密后的字符连接成串 Next i Text1.Text = str2 由此可以看出:对字符串的连接操作,可用累加算法来完成,不过在字符串的操作中,经常要用到字符串处理函数,所以一些常用的函数功能和用法必须掌握. 考虑一下:如果要实现字符的逆序连接,该怎么办? 二、连乘算法 连乘算法的一般做法是定义一个变量t,作为乘法器使用,初值为1,设一个变量用来保存乘数。 例:求10!=1*2*3*……*10的结果并打印输出 分析: 与累加算法类似,只不过加法变成乘法。 设乘法器t,初值为1,设变量I存放乘数。 当I=1时,T=T*I=1*1=1 当I=2时,T=T*I
6、1*2=2 当I=3时,T=T*I=2*3=6 …… 当I=10时,T=T*I=1*2*3*……*9*10 所以当I的值从1变化到10的过程中,乘法器均执行同一个操作:S=S*I,程序段可写成: Dim I As Integer, T As long T= 1 For I = 1 To 10 T = T* I Next I Print ”1*2*3*……*10=";T 例:求1!+2!+……+10!的值 分析: 这一题总体上是累加题,只不过加数不再是简单的1、2、3等,而是1!、2!到10!,可考虑设一个变量s作累加器,设一个
7、变量t存放每一次的加数,累加的次数是10次,分别加上1!到10!。设循环变量i值从1变化到10,每一次循环执行一次累加操作,每次累加的加数t为i!,所以在每次累加之前,应先用连乘算法计算I!的值,可设循环控制变量j,按如下程序段完成求i!: t = 1 For j = 1 To i t = t * j Next j 结合累加算法,求!+2!+……+10!的程序段如下: Dim i As Integer, j As Integer Dim s As Long, t As Long s = 0 For i = 1 To
8、 10 t = 1 内循环 For j = 1 To i t = t * j Next j s = s + t Next i Print ”1!+2!+……+10!="; s 程序执行流程是:I=1,计算t=1!,s=0+1!=1! I=2,计算t=2!,s=1!+2! I=3,计算t=3!,s=1!+2!+3! ……
9、 I=10,计算t=10!,s=1!+2!+3!+4!+5!+6!+7!+8!+9!+10! 考虑一下: (1):语句t=1是否可以和s=0一样,放在外循环外? (答案:不可以!循环初始化所放置的位置要牢记以下原则:外循环初始化应放在外循环的外面,内循环初始化应放在外循环体内,内循环体外。) (2):变量s和t可以将其类型定义为Integer(整型)吗? (答案:不可以!因为8!的值就已经超过整型所能表示的最大值32767,所以s和t必须定义成长整型(Long),否则会发生溢出.) 优化: 由于n!=(n—1)!*n,即2!=1!*2,3
10、2!*3,……,10!=9!*10,所以上述程序段还可进行以下的优化: Dim i As Integer, j As Integer Dim s As Long, t As Long s = 0 t = 1 ‘这时t=1不可放在循环体内 For i = 1 To 10 t = t * i s = s + t Next i Print ”1!+2!+……+10!="; s 执行流程为: I=1,计算t=1*1=1!,s=0+1!=1! I=2,计算t=1!*2=2!,s=1!
11、2! I=3,计算t=2!*3=3!,s=1!+2!+3! …… I=10,计算t=9!*10=10!,s=1!+2!+3!+4!+5!+6!+7!+8!+9!+10! 归纳一下: 所有累加次数确定的累加程序都可以采用如下的编程模式: 定义累加器s,初值为0或根据情况赋一个特定值,设变量t存放加数,假设累加次数为n次,则程序段可按如下框架编写: s = 0 For i = 1 To n 将加数赋给t s = s + t Next I 统计算法 如果在
12、编程时需要计算满足某一条件的量有多少个时,就可以采用统计算法。统计算法的一般做法是定义若干个变量用来作计数器,专门来统计满足相应条件的量,有多少个统计要求,就定义多少个计数器,在程序设计过程中,分别判断是否满足指定条件,若满足条件,则指定的计数器加1。如果计数器太多,而且相互之间有联系时,一般会定义一个计数器数组. 例:在文本框中输入一串字符,统计其中的字母、数字和其他字符的个数。 基本思路: 要统计满足指定要求的字符个数,应定义相应变量(如n)作为计数器,初值为0,每找到符合条件的字符,将指定计数器的值加1。 本题需要定义3个计数器n1、n2、n3,初值为0,对字符串的字
13、符逐个判断,如果是字母,n1加1,如果是数字,n2加1,否则n3加1 Private Sub Command1_Click() Dim str As String, i As Integer, ch As String * 1 Dim n1 As Integer, n2 As Integer, n3 As Integer n1 = 0: n2 = 0: n3 = 0: str = Text1。Text For i = 1 To Len(str) ch = Mid(str, i, 1) If UCase(ch) 〈= "Z" And UCase(c
14、h) >= ”A” Then n1 = n1 + 1 ‘计数器n1加1 ElseIf ch 〉= ”0” And ch 〈= "9” Then n2 = n2 + 1 ‘计数器n2加1 Else n3 = n3 + 1 ‘计数器n3加1 End If Next i Text2 = “字母的个数为" & n1 & Chr(13) & Chr(10) Text2= Text2 & “数字的个数为” & n2 & Chr(13) & Chr(10) Text2= Text2 & “其
15、他字符的个数为” & n3 End Sub 求最大值和最小值 在N个数中求最大值和最小值的思路是定义一个变量假设为max,用来存放最大值,定义一个变量假设为min,用来存放最小值。一般将第1个数赋给max和min,将剩下的每个数分别和max、min比较,如果比max大,将该数赋给max,如果比min小,将该数赋给min,即让max中总是放当前的最大数,让min中总是放当前的最小值,这样当所有数都比较完时,在max中放的就是最大数,在min中放的就是最小数。 例:随机产生20个1到100之间的整数,打印输出其最大值和最小值。 任何一个随机整数 x都可通过随机函数来
16、产生,随机函数Rnd( )可产生在0到1之间均匀分布的随机数。 要产生在区间[ M,N ]之间的随机整数x ,可用以下公式完成: x = Int( Rnd*(N- M+1))+N 所以1到100之间的随机整数 x 的产生可用以下语句完成: x = Int(Rnd*100)+1 按照求最大值和最小值的算法思想,可编写程序如下: Private Sub Form_click() Dim i As Integer, x As Integer Dim max As Integer, min As Integer Randomize
17、‘ 随机函数初始化 max = Int(Rnd * 100) + 1 min = max ‘给max和min赋初值 For i = 1 To 19 x = Int(Rnd * 100) + 1 ‘产生1到100间的随机数 If x > max Then max = x If x 〈 min Then min = x Next i Print “最大值是” & max Print “最小值是” & min End Sub 素数判断 一个数如果只能被1和其本身整除,而不能被其他任何
18、数整除,那么这个数就称为素数。 我们通过下面的例子来说明判断素数算法的基本思路。 例:输入一个整数,判断它是否是素数,比如输入7,应输出“7是素数”的提示,输入24,应输出“24不是素数”的提示。 分析: 由素数的定义,判断任一个整数n是否是素数的算法是让n分别整除从2到n—1(或 n/2、sqr(n))中的每一个数,如果有一个数能被n整除,则n不是素数,如果所有的数都不能被n整除,则n是素数。这也是一个典型的循环程序,可设一个循环变量为I,让I从2变化到n—1,如果有一个I能被n整除,说明n不是素数,下面就不用再进行判断,提前跳出循环;如果所有的I都不能被n整除,最后正常结
19、束循环。 关键是如何知道跳出循环后是提前跳出还是正常退出?对于这种有两种判断结果的处理,一般采用标志变量。设一个变量,假设命名为Flag,让Flag的初值为True,如果提前跳出循环,Flag的值赋为False,跳出循环后可根据Flag的值判断是提前跳出还是正常结束。 程序如下: Private Sub Command1_Click() Dim i As Integer, n As Integer Dim flag As Boolean flag = True ‘给标志变量赋初值 n = Val(Text1。Text) For i
20、 = 2 To n — 1 If n Mod i = 0 Then flag = False ‘如果I能被n整除,将flag赋值为False Exit For End If Next i If flag = True Then ‘该条件也可写成If flag Then MsgBox n & "是素数” Else MsgBox n & "不是素数" End If End Sub 另一种方法: 还可以在循环结束后通过循环控制变量的值来进行素数的判断。如果是素数,循环将正常结束
21、循环控制变量将超过终值;如果不是素数,肯定有一个数能够被n整除,循环会提前结束,循环控制变量小于等于终值。 程序如下: Private Sub Command1_Click() Dim i As Integer, n As Integer n = Val(Text1.Text) For i = 2 To n — 1 If n Mod i = 0 Then Exit For Next i If i = n Then ‘该条件也可写成If flag Then MsgBox n & ”是素数"
22、Else MsgBox n & "不是素数” End If End Sub 求最大公约数 求任意两个正整数的最大公约数可用辗转相除法来求。 假设要求任两个整数m和n的最大公约数,用辗转相除法的步骤是: 求m和n的余数r,将n的值作为m的新值,将r的值作为n的新值,再不断的求新的m和n的余数r,直到r的值等于0为止,这时m的值就是要求的最大公约数。 注意:由于循环程序次数不确定,应采用do—loop循环结构。 例:在两个文本框Text1和Text2中分别 输入两个正整数,单击命令按钮Command1后在窗体上输出其最大公约数
23、 程序如下: Private Sub Command1_Click() Dim m As Integer, n As Integer Dim r As Integer ‘定义存放余数的变量r m = Val(Text1.Text) n = Val(Text2。Text) Print m; ”和”; n; ”的最大公约数为”; Do r = m Mod n m = n n = r Loop Until r = 0 Print m End Sub 考虑一下:可以将第一条print语句
24、放在执行循环以后吗? (答案:不可以。因为执行完循环后m和n已经不是原来的数值了) 将以上程序添加相应语句就可完成求最小公倍数的功能(M和n的最小公倍数等于m*n/m和n的最大公约数)。 程序如下: Private Sub Command1_Click() Dim m As Integer, n As Integer Dim r As Integer Dim t As Integer m = Val(Text1.Text) n = Val(Text2.Text) t = m * n ‘记录m*n的初始值 Print m; "
25、和”; n; ”的最大公约数为"; Do r = m Mod n m = n n = r Loop Until r = 0 Print m; ”,最小公倍数为"; t / m End Sub 穷举算法 穷举法是循环程序中具有代表性的基本应用之一。穷举是一种重复型算法。它的基本思想是对问题的所有可能状态都一一测试,直到找到答案或将全部可能状态都测试过为止。 循环控制有两种办法:计数法和标志法。计数法用于循环次数确定的情况下,一般用For-Next循环比较方便;标志法用于循环次数未知情况,表示达到某一目标后使循环结束.
26、 例:搬砖问题:36块砖,36人搬,男搬4,女搬3,两个小孩搬一砖,要求一次全搬完,问男、女和小孩各有多少个? 分析: 假设男人用变量man表示,女人用women表示,小孩用children表示,有以下式子成立: men+women+children=36 4*men+3*women+children/2=36 如果用算术来解方程,可以看出这是一个典型的不定方程,可能有多个解. 穷举法的算法思想是将所有可能的情况全部列出来,逐一进行测试。 由条件可知: 男人(men)的可能取值范围为:0~8 女人(women)的可能取值范围为:0~
27、11 可利用双重循环实现对所有可能的男人men和女人women的值进行选择 children=36—men-women 如果满足 4*men+3*women+children/2=36 则表示找到一个合理的解。 Private Sub Form_Click() Dim men As Integer, women As Integer Dim children As Integer For men=0 To 8 ‘men取所有可能的值 For women=0 To 11 ‘women取所有可能的值 children=36—m
28、en–women ‘算出children的人数 If 4*men+3*women+children/2=36 Then Print "男人有:”; men; ”人" Print "女人有:"; women; ”人” Print "小孩有:"; children; "人” End If Next women Next men End Sub 精确迭代算法 迭代是一个不断用新值取代旧值或用旧值推出新值的过程。 迭代算法的程序编制时要从三方面着手:确定迭代公式(也就是循环体的内容)、公式的初始化以及迭代的终止条
29、件. 如果每次迭代都可以得到精确值,并且迭代的次数确定,这就是精确迭代算法. 例:兔子繁殖问题: 意大利数学家Fibonacci曾提出一个有趣的问题:设有一对新生兔子,从第三个月开始它们每个月都生一对兔子。按此规律,并假设没有兔子死亡,一年后共有多少对兔子。可以发现每月的兔子数组成如下数列: 1,1,2,3,5,8,13,21,34,…… 打印数列的前20项,且一行输出5个 对数列1,1,2,3,5,8,13,21,34,……可看出: 数列从第3项开始,每1项都是其前2项之和. 假设第1项元素用f1表示,第2项元素用f2表示,每次新元
30、素用f 表示 f1 f2 f 第3月 1 1 f=f1+f2=2 第4月 1 2 f=f1+f2=3 第5月 2 3 f=f1+f2=5 第6月 3 5 f=f1+f2=8 …… f1和f2初值为1 f=f1+f2 f1=f2 f2=f 可以看出: 每
31、1个月的兔子数f 要由前面的兔子数f1和f2 推出,并在求下1个月的兔子数之前要用新值对f1和f2的值进行更新。这就是迭代算法. 如果迭代的次数确定,可以得到一个确定的值,这样的迭代称为精确迭代. 程序如下: Private Sub Form_click() Dim f1 As Integer, f2 As Integer Dim i As Integer,f As Integer f1 = 1: f2 = 1 ‘给f1和f2赋初值 Print f1; f2; For i = 3 To 20 f = f1 + f2 f1 = f2 f2
32、 = f Print f; ‘输出每月的兔子数 If i Mod 5 = 0 Then Print ‘控制每行输5个 Next i End Sub 近似迭代算法 一元高次方程的求解没有通用的求根公式,常用迭代法来求方程的近似根。 迭代法求方程f(x)=0的根是将其改写为: x=ψ(x) 选取适当的初值x0,便可通过重复迭代构造序列:x0,x1,x2,……,xn,…… 若该数列收敛,则极限值就是方程的一个解。 牛顿迭代法和二分迭代法都是对一元高次方程求解的近似方法. (1)、牛顿迭代法 牛顿迭代法求f(x)=
33、0的根是在根的附近找一个初值作为x0,过x0做方程的切线,与x 轴的交点为x1,再过x1作切线,交x轴于点x2,……。可以知道,只要给定一个初始值x,通过以上操作,可不断的得到新的值x,并且x无限的接近函数在x轴的交点,即方程的根。所以经过若干次迭代后,可得到方程较高精度的近似根。牛顿切线法迭代公式为 xi+1 = xi - f(xi)/f’(xi) 其中:f’(xi)是f(xi)的导数,当|xi+1—xi|≤ε或|f(xi)|≤ ε时, xi+1就作为方程的近似根。 例:编写程序,利用牛顿迭代法求方程xex -1=0在x0=0。5附近
34、的一个根,要求精确到10—7 算法分析: 1、循环初值 x=0。5 2、迭代公式 x = x-(xex-1)/(xex+ex) (循环体的内容) 3、结束条件: | xex-1|<10-7 程序如下: Private Sub Command1_Click() Dim x As Single, Eps As Single x=InputBox("输入初始值x:”, "牛顿迭代法”) Eps=InputBox("输入允许误差Eps","牛顿迭代法") Do x =x-(x*Exp(x)—1)/(Exp(x)*x+Exp(x)) Loop
35、Until Abs(x*Exp(x)—1)<=Eps Text1.Text=Str(x) End Sub (2)、二分迭代法算法 例:设计一个用二分法求方程x3-x4+4x2-1=0在区间[0,1]上的一个实根. 算法思路: 若方程f(x)=0在区间[a,b]上有一个实根,则f(a)与f(b)一定异号。二分法的思想是在区间[a,b]上取中点c=(a+b)/2,若f(a)*f(c)〈0,则实根在区间[a,c]中,将c赋给b;若f(a)*f(c)>0,则实根在区间[c,b]中,将c赋给a;构成新区间[a,b],再取中点c,继续做如上操作,直到|a—b|的值小于给定的误差精
36、度值,这时a或b就是方程的根. 程序如下: Private Sub Form_click() Dim a As Single,b As Single,c As Single,e As Single e = InputBox("请输入误差精度") a = 0: b = 1 Print “在误差" & e & “范围内,方程在[0,1]上的根为:"; Do c = (a + b) / 2 If (a^3 -a^4+4*a^2—1)*(c^3—c^4+4*c^2—1)〈0 Then b = c Else a = c End
37、 If Loop Until Abs(a — b) 〈 e Print a End Sub 十进制转换为N进制 一个十进制正整数 m 转换成n 进制数的思想是:将 m 不断除以n 取余数,直到商为零,将余数逆序排放即可. 1、把任意一个十进制正整数转换成2进制数 (1)、可以看出:这是一个典型的循环程序,由于次数不确定,考虑采用Do-Loop型结构. Do While m 〉 0 r = m Mod 2 ‘求余数 m = m \ 2 … Loop (2)、要将余数逆序连
38、接成二进制数,可定义一个字符串变量str,利用字符串连接符进行连接. str = r & str 程序如下: Private Sub Command1_Click() Dim m As Integer, str As String, r As Integer m = Val(Text1。Text) Do While m > 0 r = m Mod 2 str = r & str m = m \ 2 Loop Text2。Text = str End Sub Private Sub Command2_Click() End E
39、nd Sub 2、把任意一个十进制正整数转换成8进制数 程序如下: Private Sub Command1_Click() Dim m As Integer, str As String, r As Integer m = Val(Text1。Text) Do While m 〉 0 r = m Mod 8 str = r & str m = m \ 8 Loop Text2。Text = str End Sub Private Sub Command2_Click() End End Sub 3、把任意一个十进
40、制正整数转换成16进制数 可以看出:将十进制数转换为十六进制数时,由于余数r可能超过10,所以对超过10的余数要进行转换。 转换的对应关系为: 10 11 12 13 14 15 A(65) B(66) C(67) D(68) E(69) F(70) 对应的字符为: chr(r+55) 程序如下: Private Sub Command1_Click() Dim m As Integer, str As String, r As Integer m = Val(Text1。Text)
41、 Do While m > 0 r = m Mod 16 If r < 10 Then str = r & str Else str = Chr(r + 55) & str End If m = m \ 16 Loop Text2 = str End Sub N进制转换为十进制 一个N进制数转换成十进制数的思想是:将该N进制数各位数字按权展开再求和. 1、把任意一个2进制正整数转换成十进制数 ( 1 1 0 1)2=1* 23+1* 22 +0* 21 +1* 20=(13)10
42、 (1)、截取二进制字符串str的每个字符 ch =Mid (str ,i,1) i=1……len (str) (2)、最高位的权值p为: n=len (str) : p=2^(n-1) (3)、用累加算法求转换后的十进制数s: s=s+val(ch)*p : p=p/2 ‘产生下一个数的权值 程序如下: Private Sub Command1_Click() Dim i As Integer,n As Integer,p As Integer Dim s As Integer,str1 As String
43、str1 = Text1。Text n = Len(str1) p = 2 ^ (n — 1) For i = 1 To n s = s + Val(Mid(str1, i, 1)) * p p = p / 2 Next i Text2.Text = str(s) End Sub 2、把任意一个8进制正整数转换成十进制数 ( 1 7 4 )8=1* 82+7* 81 +4* 80=64+56+4=(124)10 可以看出:把8进制数转换为十进制数的算法与2进制数转换为十进制数的算法完全相同。 程序如下: Private Sub C
44、ommand1_Click() Dim i As Integer,n As Integer,p As Integer Dim s As Integer,str1 As String str1 = Text1.Text n = Len(str1) p = 8 ^ (n - 1) For i = 1 To n s = s + Val(Mid(str1, i, 1)) * p p = p / 8 Next i Text2。Text = str(s) End Sub 3、把任意一个16进制正整数转换成十进制数 ( 1 7 C )8=1*
45、 162+7* 161 +12* 160=256+112+12=(380)10 可以看出:把16进制数转换为十进制数的算法与其他算法相似,只不过当截取的字符为A到F时,要将其转换为对应的数值。 转换的对应关系为: A(Ascii码为65) B(66) C(67) D(68) E(69) F(70) 10 11 12 13 14 15 假设截取的字符为ch,则字符对应的数值为: asc(ch)-55 Private Sub Command1_Click() D
46、im i As Integer, n As Integer, p As Integer Dim s As Integer, str1 As String, ch As String str1 = Text1.Text : n = Len(str1) p = 16 ^ (n — 1) For i = 1 To n ch = Mid(str1, i, 1) If ch >= "A” And ch 〈= "Z" Then s = s + (Asc(ch) — 55) * p Else s = s + Val(ch) * p
47、End If p = p / 16 Next i Text2.Text = str(s) End Sub 字符加密 将输入的原字符串的每个字符按指定的规则进行转换,得到新字符,将每个新字符连接成新串就可以实现对字符串进行加密. 对字符串的每个字符的解密过程与上述相同,只是规则正好与上面的加密规则相反。 例:输入一串字母,按以下规则进行加密:将每个原码字母在A—Z-A首尾相连的字母表上向后移6位为译码。如下表所示: 原码 A B C …… X Y Z 译码 G H I …… D E F (1)、截取字符串str
48、的每个字符 ch =Mid(str,i,1) i=1……len(str) (2)、对字符串中每个字符的转换关系为: A(Ascii码为65) B(66) C(67) D(68) …… T(84) G(Ascii码为71) H(72) I(73) J(74) …… Z(90) 可以看出:转换后字符的Ascii码为n=asc(ch)+6 转换后的字符串str1=str1+chr(n) 考虑一下:当字符为U到Z时,转换后的字符就超过Z的范围。 (3)、对U到Z之间的字符的转换关系为:
49、 U(Ascii码为85) V(86) W(87) X(88) Y(89) Z(90) A(Ascii码为65) B(66) C(67) D(68) E(69) F(70) 可以看出: 当转换后字符的Ascii码n=asc(ch)+6超过90时 转换后的字符串str1=str1+chr(n—26) 程序如下: Private Sub Command1_Click() Dim str1 As String, str2 As String Dim n As Integer, ch As String * 1, i As Integer str1 = UCase(Trim(Text1。Text)) For i = 1 To Len(str1) ch = Mid(str1, i, 1) n = Asc(ch) + 6 If n 〈= 90 Then str2 = str2 + Chr(n) Else str2 = str2 + Chr(n - 26) End If Next i Text2。Text = str2 End Sub






