温馨提示: 定期 清理浏览器缓存,可以获得最佳浏览体验。
New!
lianxh
命令发布了:
随时搜索连享会推文、Stata 资源,安装命令如下:
. ssc install lianxh
使用详情参见帮助文件 (有惊喜):
. help lianxh
⛳ Stata 系列推文:
作者: 冯超楠 (北京航空航天大学)
邮箱: fengcnhpy@126.com
目录
除了官方命令外,Stata 还允许用户自己编写 ado 程序文件,例如非官方命令 outreg2
。ado 文件的编辑也相对简单,只需在 Do-file 编辑器中写入相应代码,然后保存为 .ado 格式。为了让大家对 ado 文件编辑有更好的认识,本文在推文「Stata 程序:10 分钟快乐编写 ado 文件」 的基础上,以计算最大公约数和最小公倍数实例来分享程序编写的具体思路和步骤。
同时,若是家中有正在学「公约数」和「公倍数」概念的小朋友,也可以让他们读读这篇推文,换个角度感受一下,或许小家伙会因此对「经济学」或「计量经济学」产生兴趣。
最大公约数是指两个或多个整数共有约数中最大的一个。在这里,我们将
求 (319, 377)
∵ 319 ÷ 377 = 0 (余 319)
∴ (319, 377) = (377, 319)
∵ 377 ÷ 319 = 1 (余 58)
∴ (377, 319) = (319, 58)
∵ 319 ÷ 58 = 5 (余 29)
∴ (319, 58) = (58, 29)
∵ 58 ÷ 29 = 2 (余 0)
∴ (58, 29) = 29
∴ (319, 377) = 29
对于用「辗转相除法」求 3 个数及以上的最大公约数,可以先求出其中 2 个数的最大公约数,再求这个最大公约数与第 3 个数的最大公约数,依次类推,直到最后一个数为止。并且,最后得到的最大公约数,就是所有数的最大公约数。
最小公倍数是指两个或多个整数的公倍数中除 0 外最小的一个。在这里将
由于最大公约数与最小公倍数间具有如下关系:
所以,求两个数的最小公倍数,就可以先求出它们的最大公约数,然后再用上述公式求出它们的最小公倍数。
求 [18, 20]
[18, 20] = 18 × 20 ÷ (18, 20) = 18 × 20 ÷ 2 = 180
对于求 3 个数及以上的最小公倍数,可以先求出其中 2 个数的最小公倍数,再求这个最小公倍数与第 3 个数的最小公倍数,以此类推,直到最后一个为止。最后得到的最小公倍数,就是所有数的最小公倍数。
为简便起见,我们先计算 1 个或 2 个自然数的最大公约数。在 Stata 中,可以通过条件命令 if
来判断输入自然数的个数:
while
循环命令和 mod
取余命令实现「辗转相除法」计算最大公约数;最后使用 dis
命令在屏幕上显示计算结果。详细代码如下:
* Greatest Common Denominator (GCD) of 2 integers
cap program drop gcd
program define gcd
if "`2'" == "" {
dis `1'
}
else {
while `2' {
local temp2 = `2'
local 2 = mod(`1',`2')
local 1 = `temp2'
}
dis `1'
}
end
gcd 100
gcd 5 10
结果如下:
. gcd 100
100
. gcd 5 10
5
考虑到计算最小公倍数时,需引用最大公约数的计算结果,因此我们要将该结果保存,而非仅在屏幕上显示。此时,可以使用 program define, rclass
命令,返回值将被存储到 r()
中。当然,还可以使用 eclass
和 sclass
命令,结果将分别保存在 e()
和 s()
中。详细代码如下:
* Greatest Common Denominator (GCD) of 2 integers
cap program drop gcd
program define gcd, rclass
if "`2'" == "" {
return scalar gcd = `1'
}
else {
while `2' {
local temp2 = `2'
local 2 = mod(`1',`2')
local 1 = `temp2'
}
return scalar gcd = `1'
}
end
gcd 100
dis r(gcd)
gcd 5 10
dis r(gcd)
结果如下:
. gcd 100
. dis r(gcd)
100
. gcd 5 10
. dis r(gcd)
5
通过存储最大公约数的计算结果,我们可以调用 gcd
函数来计算最小公倍数。详细代码如下:
* Least Common Multiple (LCM) of 2 integers
cap program drop lcm
program define lcm, rclass
if "`2'" == "" {
return scalar lcm = `1'
}
else {
gcd `1' `2'
return scalar lcm = `1' * `2' / r(gcd)
}
end
lcm 100
dis r(lcm)
lcm 5 10
dis r(lcm)
. lcm 100
. dis r(lcm)
100
. lcm 5 10
. dis r(lcm)
10
在使用「辗转相除法」求几个数的最大公约数时,我们可以先求出其中任意 2 个数的最大公约数,再求这个最大公约数与第 3 个数的最大公约数,以此类推。因此,我们只需循环调用 gcd
函数,最小公倍数也是一样。详细代码如下:
* GCD of arbitrarily long list of integers
cap program drop gcdm
program define gcdm, rclass
clear results
foreach i of local 0 {
gcd `i' `r(gcd)'
}
return scalar gcd = r(gcd)
di "`r(gcd)'"
end
* LCM of arbitrarily long list of integers
cap program drop lcmm
program define lcmm, rclass
clear results
foreach i of local 0 {
lcm `i' `r(lcm)'
}
return scalar lcm = r(lcm)
di "`r(lcm)'"
end
gcdm 5 10 15
lcmm 5 10 15
. gcdm 5 10 15
5
. lcmm 5 10 15
30
考虑到用户可能会输入负数或小数导致无法计算最大公约数和最小公倍数,因此我们需要在前文的基础上增加报错机制,即一旦用户输入内容无法用来计算最大公约数和最小公倍数,则报错并提示用户正确输入正整数。以计算最大公约数为例,详细代码如下:
* GCD of arbitrarily long list of integers
* Greatest Common Denominator (GCD) of long list of integers
capture program drop gcdm
program define gcdm,rclass
clear results
capture syntax anything(name=n)
if _rc{ // 用户忘了输入数字
dis as error "You must enter positive integers"
exit
}
tokenize "`n'"
local j = 1
while "``j''" !=""{ // `j' 表示房间号;``j'' 表示房间中的内容
local k = ``j'' // 注意暂元的引用方式
capture confirm integer number `k' // 用户输入了非整数或文字
if _rc{
dis as error "You must enter positive integers"
exit
}
if `k'<= 0{ // 用户输入了负数
dis as error "You must enter positive integers"
exit
}
gcd `k' `r(gcd)'
local j = `j' + 1
}
return scalar gcdm = r(gcd)
end
gcdm
gcdm 10.5
gcdm -10
gcdm 100 200 50
dis r(gcdm)
. gcdm
You must enter positive integers
. gcdm 10.5
You must enter positive integers
. gcdm -10
You must enter positive integers
. gcdm 100 200 50
. dis r(gcdm)
50
为了检查用户输入内容是否均为正整数,我们需要对输入内容进行拆分,并逐个检查。在这里,首先使用 capture syntax anything(name=n)
解析命令行,将输入内容命名为 n,并结合 capture
命令检查用户是否输入内容。之后使用 tokenize
命令对字符串 n 进行拆分,默认以空格作为各个部分的分隔符,也可通过选项进行分隔符的指定。随后,使用 capture confirm integer number
或 if
命令检验用户输入了非整数、文字或负数,一旦发生用户输入内容符合以上几种无法计算最大公约数和最小公倍数的情况,则在屏幕上进行报错提示 "You must enter positive integers" 后直接运行 exit
命令。
通过前面的部分,我们已经大致了解了编写程序的思路和基本步骤。接着,我们试图将计算结果赋给指定变量名的新变量。以计算最大公约数为例,具体代码如下:
* Greatest Common Denominator (GCD) of 2 integers
capture program drop gcd
program define gcd,rclass
if "`2'" == "" {
return scalar gcd =`1'
}
else {
while `2' {
local temp2 = `2'
local 2 = mod(`1',`2')
local 1 = `temp2'
}
return scalar gcd = `1'
}
end
* Greatest Common Denominator (GCD) of 2 integers
capture program drop gcdm
program define gcdm,rclass
clear results
capture syntax anything(name=n)[,GENerate(string) replace]
if _rc{ // 用户忘了输入数字
dis as error "You must enter positive integers"
exit
}
if "`generate'" != ""{
if "`replace'" != "" {
capture drop `generate'
}
gen `generate' = .
}
tokenize "`n'"
local j = 1
while "``j''" !=""{ // `j' 表示房间号;``j'' 表示房间中的内容
local k = ``j'' // 注意暂元的引用方式
capture confirm integer number `k' // 用户输入了非整数或文字
if _rc{
dis as error "You must enter positive integers"
exit
}
if `k'<= 0{ // 用户输入了负数
dis as error "You must enter positive integers"
exit
}
gcd `k' `r(gcd)'
local j = `j' + 1
}
if "`generate'" != ""{
replace `generate'= r(gcd)
}
return scalar gcdm = r(gcd)
// di r(gcdm)
// di "`r(gcdm)'"
end
clear
set obs 3
gen x = 1
gen mm=1
gcdm 100 200 50 30 20 60 80 60, gen(mm) replace
dis r(gcdm)
list if _n<=1
gcdm 100 200 50,gen(mm) replace
dis r(gcdm)
list if _n<=1
. gcdm 100 200 50 30 20 60 80 60, gen(mm) replace
(3 missing values generated)
(3 real changes made)
. dis r(gcdm)
10
. list if _n<=1
+--------+
| x mm |
|--------|
1. | 1 10 |
+--------+
.
. gcdm 100 200 50,gen(mm) replace
(3 missing values generated)
(3 real changes made)
. dis r(gcdm)
50
. list if _n<=1
+--------+
| x mm |
|--------|
1. | 1 50 |
+--------+
capture syntax anything(name=n)
后选项 [,GENerate(string) replace]
的添加,允许用户使用命令 generate
生成新变量并存储计算结果,若使用 generate replace
命令则会替换原有的变量。
在编写完一个命令之后,无论是自己还是他人使用,我们都希望能有帮助文档对命令的用法进行说明。由于本文只是为大家简要介绍如何编写 ado 文件,因此编写的帮助命令也是最基础的。以 gcdm
为例,在 Do-file 编辑器中写完帮助文件后,保存为 .sthlp 格式即可。
{smcl}
{* 9 Dec 2020}{...}
{hline}
help for {hi:gcdm}
{hline}
{title:Title}
{p 4 4 2}
{bf:gcdm} —— Compute the Greatest Common Denominator (GCD) of Positive Integers
{title:Syntax}
{p 4 4 2}
{cmdab:gcdm} {anything},
[
{cmdab:g:enerate}{cmd:(}varname{cmd:)} {cmd:replace}
]
{title:Description}
{p 4 4 2}
{cmd:gcdm} makes it easy for users to compute the greatest common denominator (GCD) of positive integers
and the result is stored in r(gcdm).
{title:Options}
{phang}
{cmdab:g:enerate(}{it:varname}{cmd:)} Specifies the name for the greatest common denominator (GCD) variable.
{p_end}
{phang}
{cmd:replace} Specifies that an existing variable is to be overwritten with parameter draws.
{p_end}
{title:Examples}
{p 4 4 2} *- Calculate the greatest common denominator (GCD) of 5 10 15 30. {p_end}
{p 4 4 2}{inp:.} {stata `"gcdm 5 10 15 30"'}{p_end}
{p 4 4 2}{inp:.} {stata `"dis r(gcdm)"'}{p_end}
{p 4 4 2} *- Calculate the greatest common denominator (GCD) of 5 10 15 30 and generate a new variable to store it {p_end}
{p 4 4 2}{inp:.} {stata `"clear"'}{p_end}
{p 4 4 2}{inp:.} {stata `"set obs 3"'}{p_end}
{p 4 4 2}{inp:.} {stata `"gen x = 1"'}{p_end}
{p 4 4 2}{inp:.} {stata `"gcdm 5 10 15 30,gen(gcd_result) replace"'}{p_end}
{title:Author}
{p 4 4 2}
{cmd:Chaonan,Feng}{break}
School of Economics and Management, Beihang University.{break}
E-mail: {browse "mailto:fengcnhpy@126.com":fengcnhpy@126.com}. {break}
最后,我们可以将自己编写的命令发布到相关平台上供用户使用,例如 ssc、github、gitee 等,详细过程见「Stata 程序:10 分钟快乐编写 ado 文件」。
Note:产生如下推文列表的 Stata 命令为:
lianxh 程序, m
安装最新版lianxh
命令:
ssc install lianxh, replace
免费公开课
最新课程-直播课
专题 | 嘉宾 | 直播/回看视频 |
---|---|---|
⭐ 最新专题 | 文本分析、机器学习、效率专题、生存分析等 | |
研究设计 | 连玉君 | 我的特斯拉-实证研究设计,-幻灯片- |
面板模型 | 连玉君 | 动态面板模型,-幻灯片- |
面板模型 | 连玉君 | 直击面板数据模型 [免费公开课,2小时] |
⛳ 课程主页
⛳ 课程主页
关于我们
课程, 直播, 视频, 客服, 模型设定, 研究设计, stata, plus, 绘图, 编程, 面板, 论文重现, 可视化, RDD, DID, PSM, 合成控制法
等
连享会小程序:扫一扫,看推文,看视频……
扫码加入连享会微信群,提问交流更方便
✏ 连享会学习群-常见问题解答汇总:
✨ https://gitee.com/arlionn/WD
New!
lianxh
命令发布了:
随时搜索连享会推文、Stata 资源,安装命令如下:
. ssc install lianxh
使用详情参见帮助文件 (有惊喜):
. help lianxh