Python常用科学计算库简介
Python中很多比较成熟的科学计算库,例如用于简单数据操作的numpy,以及基于numpy更为强大的scipy,符号计算库sympy等等,一部分库是由NUMFOCUS组织所维护(https://numfocus.org)。下面我将对这些库做一些简短说明,以后会有逐个较为详细的说明。
numpy (http://www.numpy.org)numpy应该是python中最出名的数据处理库了,他的底层调用的是intel的mkl库,从而计算速度相当的快。这里要注意的一点是用纯Python写的脚本一般而言执行起来会很慢,由于Python是胶水语言,从而一些计算密集型的操作最好是用更底层的语言C/Fortran去实现,然后通过Python来调用。numpy主要常用于对数组进行操作,很多功能类似于MATLAB中的数组,专门用来处理数据的语言一般都会支持对数组进行整体操作,而不用循环进行操作,这样可以使得敲代码的时候更像是在敲公式,而不过多的关心非数学的东西。numpy中的基础数据类型是ndarray(可用于isinstance的判断),通过调用array来实现,例如定义一个一维数组A。 ...
Python简介
Python中可以用于迭代的对象都称之为迭代器,还有一类特殊的迭代器被称为生成器。例如list就可被当做迭代器,而range就是生成器(Python2.7中对应的是xrange)。生成器的迭代元素是在迭代时才会被计算出来,而不是一开始就全部计算出来,这样做可以节省内存,但是运算时间会变长。在介绍这些之前先补充一些list中容易遇到的坑(其实就是我遇到过的)。
坑我是做输运模拟的,所以写代码希望更数学一些,因而总是想和MATLAB、Fortran中的一些用法做对应,从而会有些对我而言比较奇怪的坑。
12341 L = [[1,2,3], [4,5,6], [7,8,9]]2 a = L[2] # a = [7,8,9]3 b = L[:][2] # b = [7,8,9]4 c = a.append(4) # c = None
上述a输出的是L的最后一个元素,结果就是[7,8,9],b这样写,我的本意是想输出[3,6,9],也就是说将这里的L看作为了一个矩阵,我想输出最后一列,但其实list仅仅是一个类似于一维数 ...
Python数据结构
昨天简单的介绍了一下Python中常用的一些内建(build-in)的数据结构,今天举一些具体的例子,并对这些数据结构的API做一个简单的说明。
list12345678910111213141516171819202122232425262728293031323334353637# 初始化空list,也可以是 a = []a = list() # a = []# 也可以直接初始化一个含有元素的lista = [1,2,3] # a = [1,2,3]# list尾部添加一个元素a.append(5) # a = [1,2,3,5]# 一次性在list尾部添加多个元素a.extend([7,1,2]) # a = [1,2,3,5,7,1,2]# 计算该list中某个元素有多少个a.count(1) # 返回2# 返回元素的指标indexa.index(7) # 返回4,元素重复则头一个# 指定位置插入新的元素# 第一个变量是位置,第二个是插入元素值a.insert(3,6) # a = [1,2,3,6,5,7,1,2]# 删除元素a.remove(7) # a = ...
Fortran调用C++
在Fortran中我们偶尔会去调用已经用C++写好的代码,要实现这个功能就需要写好接口程序,开发人员已经将接口抽象出来,也就意味着我们不需要在汇编的级别进行编写。今天讲的是Fortran调用C++,调用C语言接口会有些不同,今天不讲关于调用C语言的内容。
Fortran中有很多内建函数和内建模块可供使用,一部分是为了解决各种版本的编译器之间的兼容问题,例如iso_fortran_env模块中包含了各种数据类型的kind信息,gfortran中定义双精度浮点型变量是通过real(8)实现的,但是有些编译器这里的数字不一定是8。在模块iso_fortran_env中有一些常量可以避免这些问题,例如real64,定义双精度浮点数的时候就可以利用real(real64)来进行声明,也就是不用管那个括号里应该是什么。另一个模块iso_c_binding里含有的就是Fortran和C++交互的信息。
例子:
由于是Fortran和C++交互,从而有两段代码。
File: sub.cpp
12345678910111213141516171 #include<cmath>2 ...
Fortran其他语句
今天介绍的是Fortran中一些零零散散的语句,有些之前提到过,不过没有细讲。
forallforall是一种并行的循环,也就是说,在forall程序块中的语句是一句一句执行的,并且每一句对应的所有指数的元素是同时进行计算的,这里说起来有点绕,举个例子:
123456789101112131 integer :: num(5), i2 num = 0 ! [0,0,0,0,0]3 forall(i=2:5)4 num(i) = i ! [0,2,3,4,5]5 num(i) = num(i-1) + 1 ! [0,1,3,4,5]6 end forall7 write(*,*) num8 num = 0 ! [0,0,0,0,0]9 do i=2,510 num(i) = i ! [0,2,3,4,5]11 num(i) = num(i-1) + 1 ! [0,1,2,3,4]12 end do13 write(*,*) num
这里通过do和forall语句的 ...
Fortran运算符重载和函数动态绑定
Fortran也可以进行类似C++中的运算符重载。相应的关键字都是operator。关于函数动态绑定则类似于C/C++中的函数指针,在这里称之为过程指针,不过一个意思。
运算符重载1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859601 module typedef2 implicit none3 type nums4 integer :: a, b5 contains6 procedure :: mul => mul_type7 procedure :: add => add_type8 procedure :: ass => ass_fun9 generic :: operator(+) => add10 g ...
Fortran函数接口和声明
前面有一次的教程我提到过,在Fortran中有很多种情况下定义函数需要定义接口(interface)之后才能够被调用,例如函数的返回值为数组,函数的参数不固定等。例如根据方位角得出该向量的值的函数实现:
123456789101112131415161718191 function sphere2rect(theta, phi)2 implicit none3 real, intent(in) :: theta, phi4 real :: sphere2rect(3)5 sphere2rect(1) = sin(theta)*cos(phi)6 sphere2rect(2) = sin(theta)*sin(phi)7 sphere2rect(3) = cos(theta)8 end function sphere2rect9 program main10 implicit none11 interface12 function sphere ...
Fortran面向对象
Fortran中也可以定义类似于C++中的类(class),若单单只有变量,没有函数的定义,那么就类似于C/C++中的结构体(struct)。Fortran中是通过关键字type来实现面向对象的。type的结构为:
12345type 类名 定义变量contains 定义类过程end type 类名
和C++中不同的是,在type只能声明类过程(类函数),具体实现需要放到type外面去。从而很容易想到,可以将type的声明和具体实现放到module中封装起来,会变的非常方便。
type中的公有和私有成员的声明和module中的不太一样,若要将成员都变为私有,需要在type内成员定义前进行声明private,type中不允许整体声明为公有,若要在私有环境中声明公有成员,则需将public当作成员属性进行声明(不过默认为公有环境,也可用private将成员进行私有化声明)。
type中暂时还没有实现构造函数(constructor )的实现方式,成员变量需要一一赋值。但是可以利用final声明析构函数(destructor)。
type也有类似C++中的抽象类和多态的 ...
Fortran共享变量
Fortran中不能定义全局变量,但是可以通过一些方式在主程序和函数之间实现变量的共享,这个可以通过两种方式完成,模块module和公共区common。
module模块的结构如下:
12345module 模块名 模块中的变量contains 模块中的函数end module 模块名
模块其实就是包含一些变量和函数的一个集合。只要模块中的变量都有save属性,则可以通过module实现数据的共享。gfortran中module里的变量默认就是save的。编译完含module的源代码之后,目录下会出现以module为名字的.mod文件,运行编译完成的二进制文件的时候,这些mod文件是不能删掉的。
例如我想共享常数pi的值和add函数:
1234567891011121314151 module const2 implicit none3 real, parameter :: pi=3.14159274 contains5 real function add(x, y)6 implicit none7 ...
Fortran函数和子程序
Fortran有两种实现函数调用的方式,分别是通过function和subroutine完成的。这里分别对应于C/C++中的有返回值的函数和无返回值的函数。需要注意的一点是Fortran中传参默认是传址,类似C/C++中将函数参数都定义为引用一样。下属文字中未做特殊说明,”函数”均是function和subroutine的统称。
functionfunction的结构为:
12345返回值类型 修饰符 function 函数名(参数列表) 参数声明 函数体 returnend function 函数名
返回值类型就是基本数据类型。修饰符是用来声明函数属性的,常见属性关键字有recursive(递归)、elemental(数组函数)和pure(纯函数),这些放到以后讲解。其中的return若在函数末尾就可省略,类似的主程序中program也有类似关键字stop,若放在末尾一样也可以省略。return和stop一般用来中途退出函数和结束程序。函数内的函数的返回值变量名和定义的函数名一致,若函数名过长,可以使用result关键字起一个简短的函数名称(仅在 ...