Skip to content

Commit 66db365

Browse files
committed
chap2 part
1 parent a2591a5 commit 66db365

8 files changed

+134
-21
lines changed

sample_codes/chapter2/app/main.f90

+7-13
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,11 @@
11
program main
2-
use iso_fortran_env, only: real32
3-
use julia_set_m, only: generate_julia_set, draw_julia_set
4-
use save_julia_set_image, only: julia_set_image
2+
use Stern_Gerlach_experiment ! 引入模块,从而能够使用其中定义的变量及过程
53
implicit none
6-
integer, parameter :: width = 80
7-
integer, parameter :: height = 50
8-
integer, dimension(height, width) :: julia_set
9-
complex(real32), parameter :: c = (-0.835, -0.2321)
4+
integer, parameter :: emission_times = 5 ! 实验的观察次数
5+
integer :: i
106

11-
call generate_julia_set(julia_set, -1.5, 1.5, -1., 1., c, 1000)
7+
do i = 1, emission_times
8+
call emit_atom()
9+
end do
1210

13-
call draw_julia_set(julia_set)
14-
15-
call julia_set_image(julia_set)
16-
17-
end program main
11+
end program
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
module Stern_Gerlach_experiment
2+
implicit none
3+
private
4+
public :: emit_atom
5+
6+
contains
7+
8+
subroutine emit_atom()
9+
real :: raw_number
10+
integer :: spin ! 0代表spin up,1代表spin down
11+
12+
call random_number(raw_number) ! raw_number的范围是[0,1)
13+
spin = nint(raw_number) ! 四舍五入得到0或1
14+
15+
if (spin == 0) then ! 判断spin的值,若等于0,则执行下面语句
16+
write (*, *) "Emit an atom with spin up."
17+
else ! 否则执行这一部分
18+
write (*, *) "Emit an atom with spin down."
19+
end if
20+
21+
end subroutine
22+
23+
end module

src/SUMMARY.md

+4-2
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,24 @@
33
[现代Fortran程序设计](title-page.md)
44
[序言](preface.md)
55

6+
<!--
67
## 新手村任务
78
89
- [新手村任务](./新手村任务/README.md)
910
- [查找两者之间最大的数](./新手村任务/task1.md)
1011
- [计算10的阶乘](./新手村任务/task2.md)
1112
- [根据半径求一个圆的面积](新手村任务/task3.md)
13+
-->
1214

1315
## 基础语法
1416

1517
- [初识Fortran](ch01-00-getting-started.md)
1618
- [安装Fortran开发环境](ch01-01-install-compiler.md)
1719
- [gfortran基本操作](ch01-02-gfortran.md)
1820
- [fpm基本操作](ch01-03-fpm.md)
19-
- [Fortran语言单元](ch01-04-program-unit.md)
2021

21-
- [第一个Fortran程序(暂定)]()
22+
- [第一个Fortran程序](ch02-00-first-fortran.md)
23+
- [Fortran语言单元](ch02-01-program-unit.md)
2224

2325
- [变量与数组]()
2426

src/ch02-00-first-fortran.md

+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# 第一个Fortran程序
2+
本章会讲解一个简单的小程序,一方面能让你继续熟练使用你的编程环境,另一方面是让你对Fortran有初步的了解。
3+
4+
我们会尽可能详细地讲解每一行代码的含义,但是请放心,如果你对理解特定语句暂时感到困难,请直接跳过。通过后续章节循序渐进地学习,你最终还是可以学会相关语法。
5+
6+
在命令行中执行`fpm new first-fortran`创建新项目。在fpm项目的`src`目录中新建名为`Stern_Gerlach_experiment.f90`的文件(别忘了删除默认生成的.f90文件),并将以下内容写到该文件中:
7+
```fortran
8+
module Stern_Gerlach_experiment
9+
implicit none
10+
private
11+
public :: emit_atom
12+
13+
contains
14+
15+
subroutine emit_atom()
16+
real :: raw_number
17+
integer :: spin ! 0代表spin up,1代表spin down
18+
19+
call random_number(raw_number) ! raw_number的范围是[0,1)
20+
spin = nint(raw_number) ! 四舍五入得到0或1
21+
22+
if (spin == 0) then ! 判断spin的值,若等于0,则执行下面语句
23+
write (*, *) "Emit an atom with spin up."
24+
else ! 否则执行这一部分
25+
write (*, *) "Emit an atom with spin down."
26+
end if
27+
28+
end subroutine
29+
30+
end module
31+
```
32+
接下来修改`app`中的`main.f90`,将其中的内容改为:
33+
```fortran
34+
program main
35+
use Stern_Gerlach_experiment ! 引入模块,从而能够使用其中定义的变量及过程
36+
implicit none
37+
integer, parameter :: emission_times = 5 ! 实验的观察次数
38+
integer :: i
39+
40+
do i = 1, emission_times
41+
call emit_atom()
42+
end do
43+
44+
end program
45+
```
46+
完成以上步骤后,在命令行中执行`fpm run`。如果项目能够成功编译并执行,你会在命令行中看到类似于这样的执行结果
47+
```
48+
Emit an atom with spin down.
49+
Emit an atom with spin up.
50+
Emit an atom with spin up.
51+
Emit an atom with spin down.
52+
Emit an atom with spin up.
53+
```
54+
在详细解释代码之前,我们先简要介绍这段代码所描述的物理过程。这个小程序模拟的是[施特恩-格拉赫实验](https://zh.wikipedia.org/wiki/施特恩-格拉赫实验)
55+
![施特恩-格拉赫实验](media/Stern_Gerlach_experiment.png)
56+
电子具有自旋角动量,可以产生自旋磁矩。由于其自旋角动量的取值是量子化的,且仅有两种取值(我们将其分别标记为spin up和spin down),因而磁矩也仅有两种取向。因此,如果将含有未成对电子的原子束打向非均匀的磁场,其中的原子因磁矩的不同,会偏转产生不同方向的两束原子。这个实验使人们第一次观察到原子磁矩的量子化。
57+
58+
我们的第一个程序将依次「发射一个原子」,这个原子的自旋角动量是随机的,然后程序将观察结果打印到屏幕中。
59+
60+
首先来看`Stern_Gerlach_experiment.f90`。这个文件中的`module Stern_Gerlach_experiment``end module`,以及它们包含的内容,构成了一个Fortran模块(module)。模块就像一个工具箱,把关于同一个任务的变量、函数、子程序等都打包在一起,提供给使用这个模块的程序其他部分。`Stern_Gerlach_experiment`是模块的名字,表明这个模块会提供模拟施特恩-格拉赫实验的功能。
61+
62+
`implicit none`告诉编译器,在这个模块中的所有变量,都必须显式(explicit)地声明后才能使用。我们建议你在编写程序时,始终使用这个语句,可以有效地避免出现计算结果的错误。接下来的`private`语句,会隐藏模块中的定义的所有变量和函数等内容。明明模块是为了提供给他人使用的,为什么还要隐藏其中的内容呢?有两点原因:
63+
1. 首先模块中并非所有内容都是应当对外公开的,就像一台仪器,需要用外壳将其机身封装起来,使用者只会操作其外部的按钮。模块中也有一部分是仅供模块内部使用的,将其暴露在外,使用者可能会将其修改,导致错误的结果;
64+
2. 其次,一个设计良好的模块,在完成其功能的前提下,应尽可能减少对外提供的内容。这样可以减小使用者的记忆量,更加友好。
65+
66+
`public :: emit_atom`语句说明`emit_atom`这个功能是公开的,使用了这个模块的代码就可以调用`emit_atom`
67+
68+
在这个模块中,我们只定义了一个子程序(subroutine)`emit_atom`。子程序和函数(function)都定义在模块的`contains`语句之后。与模块的定义非常相似,子程序定义在`subroutine emit_atom()``end subroutine`之中。`subroutine emit_atom()`中的括号用于放置虚参列表,不过该子程序并没有虚参,所以这里为空。
69+
```fortran
70+
real :: raw_number
71+
integer :: spin ! 0代表alpha自旋,1代表beta自旋
72+
```
73+
这两行分别定义了一个`real`类型的变量`raw_number``integer`类型的变量`spin`,在该子程序后续内容中,我们可以使用`raw_number``spin`来储存数值,并用于计算、判断等操作。`real`类型的变量类似于数学中的实数,可储存包含小数部分的数值,也被称为「浮点数」;`integer`类型的变量则类似数学中的整数,不包含小数部分。我们定义的`spin`将可能取值`0``1`,分别表示spin up状态和spin down状态。
74+
75+
在Fortran中,`!`用于标记对代码的注释。从`!`开始一直到行尾的内容都是注释。注释对程序执行不起任何作用,它只是注解代码的功能,方便阅读者理解代码,提高代码的可维护性。我们鼓励读者适当地在代码中添加注释,无论是对于自己还是其他阅读代码的人,都是有好处的。
76+
77+
接下来则是子程序的具体执行部分。
78+
```fortran
79+
call random_number(raw_number) ! raw_number的范围是[0,1)
80+
spin = nint(raw_number) ! 四舍五入得到0或1
81+
```
82+
我们首先调用了Fortran内置的子程序`random_number``raw_number`作为参数接收`random_number`执行产生的结果。`random_number`会随机产生均匀落在\\([0,1)\\)区间的浮点数,因此`raw_number`的数值就在这个范围里。
83+
84+
之后我们调用内置的函数`nint`根据`raw_number`的值四舍五入得到整数0或者1,并将该结果赋值给`spin`。这里的`=`表示赋值操作,将右边变量的值复制给左边的变量。
85+
86+
87+
88+
89+
90+
91+
92+

src/ch02-01-program-unit.md

Whitespace-only changes.
26.2 KB
Loading

src/preface.md

+6-6
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,27 @@
44

55
## 关于Fortran
66

7-
我们不打算在这里过多介绍Fortran的历史——毕竟你能很容易通过搜索引擎了解到。Fortran是一门“古老”的语言,古老到即使你以前未曾学习过Fortran,也可能听过别人对于古早Fortran代码的吐槽。但是Fortran也是一门“新”语言,因为新的语言标准仍在发布。Fortran的最新标准是Fortran 2018,下一个版本Fortran 202X也正在讨论中。
7+
我们不打算在这里过多介绍Fortran的历史——毕竟你能很容易通过搜索引擎了解到。Fortran是一门「古老」的语言,古老到即使你以前未曾学习过Fortran,也可能听过别人对于古早Fortran代码的吐槽。但是Fortran也是一门「新」语言,因为新的语言标准仍在发布。Fortran的最新标准是Fortran 2018,下一个版本Fortran 202X也正在讨论中。
88

9-
虽然Fortran也算是“通用程序语言<sup>[[wikipedia](https://en.wikipedia.org/wiki/Fortran)]</sup>,但是Fortran主要应用的领域是数值计算。Fortran内置支持创建和使用数组,而且具有积累悠久的数值算法库,使得用户能轻松地编写数值计算程序。作为强类型语言,编译时对过程接口的严格检查,也保证了Fortran程序计算结果的可靠性。此外,Fortran具有良好的并行性,语法标准即支持了[Coarray](https://en.wikipedia.org/wiki/Coarray_Fortran)并行。你也可以通过其他并行API([OpenMP](https://www.openmp.org/)[MPI](https://www.mcs.anl.gov/research/projects/mpi/)[CUDA Fortran](https://developer.nvidia.com/cuda-fortran)等)编写并行Fortran程序。
9+
虽然Fortran属于「通用程序语言<sup>[[wikipedia](https://en.wikipedia.org/wiki/Fortran)]</sup>,但是其主要应用的领域是数值计算。Fortran内置支持创建和使用数组,而且具有积累悠久的数值算法库,使得用户能轻松地编写数值计算程序。作为强类型语言,编译时对过程接口的严格检查,也保证了Fortran程序计算结果的可靠性。此外,Fortran具有良好的并行性,语法标准即支持了[Coarray](https://en.wikipedia.org/wiki/Coarray_Fortran)并行。你也可以通过其他并行API([OpenMP](https://www.openmp.org/)[MPI](https://www.mcs.anl.gov/research/projects/mpi/)[CUDA Fortran](https://developer.nvidia.com/cuda-fortran)等)编写并行Fortran程序。
1010

11-
Fortran也有一些缺点:Fortran并不适合编写通用性的应用程序。用Fortran编写GUI程序是比较困难的,也缺少对于底层的直接控制。不过Fortran提供了与C语言交互的接口。在实践中,可以使用其他语言构建程序主体,用Fortran编写计算密集的部分,两者之间通过C语言接口传递数据。
11+
Fortran也有一些缺点:Fortran并不适合编写通用性的应用程序。用Fortran编写GUI程序是比较困难的,也缺少对于计算机底层的直接控制。不过Fortran提供了与C语言交互的接口。在实践中,可以使用其他语言构建程序主体,用Fortran编写计算密集的部分,两者之间通过C语言接口传递数据。
1212

1313
在实际开发中,Fortran还有如下的一些问题。Fortran标准只提供了一些内置过程与模块,并没有标准库。对于一些常用但是标准内并未提供的函数,用户可能要么自己编写实现,要么只能去寻找散落在各处的函数库。将代码构建为可执行程序也并非容易的事,尤其是当使用了其他函数库。如果你使用makefile,你可能需要手动维护源代码之间的依赖关系。
1414

15-
好在2019年,Ondřej Čertík和Milan Curcic等人建立了[fortran-lang](https://fortran-lang.org/)社区,并开始了[Fortran Standard Library](https://github.com/fortran-lang/stdlib)(stdlib)[Fortran Package Manager](https://github.com/fortran-lang/fpm)(fpm)的开发。虽然这些项目还未完成,但我们已经能窥见到它们的强大之处。尤其是fpm,提供了包管理以及项目构建功能。这使得我们能够方便地复用他人的代码,并构建自己的函数库或程序。
15+
2019年,Ondřej Čertík和Milan Curcic等人建立了[fortran-lang](https://fortran-lang.org/)社区,并开始了[Fortran Standard Library](https://github.com/fortran-lang/stdlib)(stdlib)[Fortran Package Manager](https://github.com/fortran-lang/fpm)(fpm)等项目的开发。虽然这些项目尚处于早期版本,但我们已经能窥见到它们的强大之处。尤其是fpm,提供了包管理以及项目构建功能。这使得我们能够方便地复用他人的代码,并构建自己的函数库或程序。
1616

1717
我们希望fortran-lang社区的发展与Fortran标准的进一步演化(比如提供泛型功能)能够使Fortran这门语言继续保持其生命力,让我们能使用Fortran继续开发数值计算程序。
1818

1919
## 关于本书
2020

2121
不得不承认的一点是,早期Fortran的影响力依然存在,不仅是代码遗产,也包括各种资料与书籍。我们编写这本书的一个目的,就是推广现代Fortran的特性以及开发工具。在这本书中,我们不会讲解任何过时的特性,而是着重于那些更为安全、更为友好的语言特性。
2222

23-
此外,我们希望本书并非单纯讲解Fortran的语言特性。我们认为真正重要的是帮助初学者学会编写程序、学会构建程序。因此本书也会简单介绍一些并非Fortran本身,但是编写程序时经常要接触到的概念与知识。需要注意的是,设计与构建程序框架的范式并非唯一,且各有优劣,所以我们无意也无法介绍所有的范式。本书将主要使用模块化的程序设计——这里的“模块”既表示抽象的功能单元,也表示Fortran的一种语言单元`module`
23+
此外,我们希望本书并非单纯讲解Fortran的语言特性。我们认为真正重要的是帮助初学者学会编写程序、学会构建程序。因此本书也会简单介绍一些并非Fortran本身,但是编写程序时经常要接触到的概念与知识。需要注意的是,设计与构建程序框架的范式并非唯一,且各有优劣,所以我们无意也无法介绍所有的范式。本书将主要使用模块化的程序设计——这里的「模块」既表示抽象的功能单元,也表示Fortran的一种语言单元`module`
2424

2525
为了让初学者们更加贴近开源社区,本书选择[gfortran](https://gcc.gnu.org/fortran/)编译器和fpm作为开发工具进行讲解。我们也希望你能够参与开源社区建设。
2626

27-
我们希望本书能教会你基础的Fortran语法,编写出结构化的程序。如果你在学习和编写Fortran中有任何疑问,欢迎加入Fortran Coder群(2338021)提出你的问题。
27+
我们希望本书能教会你基础的Fortran语法,编写出结构化的程序。如果你在学习和编写Fortran中有任何疑问,欢迎加入「Fortran 初学」群(100125753)提出你的问题。
2828

2929
## 其他Fortran参考资料
3030
* [Modern Fortran](https://www.manning.com/books/modern-fortran) - Milan Curcic

src/title-page.md

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# 现代Fortran程序设计
2+
作者:[Fortran-Fans](https://github.com/fortran-fans)

0 commit comments

Comments
 (0)