贡献者: addis
相对于 Fortran 或者 Matlab 等,用 C++ 做数值计算的一个缺陷就是语言本身没有矩阵以及高维矩阵类。但我们可以用第三方库或者自己写一个。我们选择后者,原因是为了教学需要我们需要保持代码的简单易读,避免复杂的 C++ 语法。
本部分中我们将大量使用自编的 SLISC(Scientific Library in Simple C++) 矩阵库。代码可以从 GitHub 仓库下载,另外提供英文说明。该库的特点是尽量不使用 C++ 的复杂语法(如模板)和复杂的类结构,使代码便于阅读学习和修改,同时又保持相对较高的性能。SLISC 使用兼容性较高的 C++11 标准。
SLISC 库在矩阵类的基础上还实现了一些科学计算常用的功能,如线性代数运算、插值、微分方程、计时、文件和目录操作、矩阵文件读写、字符串处理、特殊函数、任意精度计算、量子力学计算等。当然,一些功能基于其他项目如 Blas、Lapack、Intel MKL、Arb、GSL、Eigen 和 Arpack。在编译时可以通过选项来决定是否使用这些依赖。
一个例子(编译方法见 “SLISC 的编译和测试”):
以下列出 SLISC 的一些特性,我们以后会详细介绍。
namespace slisc
,所有宏以 SLS_
开头。
在 SLISC 中,我们希望把矩阵进行一定程度的封装,但又几乎不损失性能。许多人使用流行的矩阵库例如 Eigen,但是其代码复杂,错误信息不容易懂,代码修改起来非常困难。例如 Eigen 的 MatrixXd
矩阵类有 6 次继承,一个 2x2 的矩阵在 gdb 里面调试的时候显示出来的变量信息是这样的:
m_data
,行数 m_rows
以及列数 m_cols
。这样的库只适合直接拿来用,不适合阅读、学习和修改,尤其是对非计算机专业的同学来说。
在 C++ 标准中,一些基本类型在内存中的长度在不同计算机上可能会不同。例如 long
有时候和 int
一样是 4 字节,而另一些时候则和 long long
一样是 8 字节。因此,SLISC 仿照 Numerical Recipe [1] 的方式,定义自己的类型名称。
Char
是 char
,即 1 字节字符或整数
Uchar
是 unsigned char
,即 1 字节无符号整数
Short
是 2 字节整数
Int
是 4 字节整数
Long
是 Int
或者 Llong
,取决于宏 SLS_USE_INT_AS_LONG
是否定义。SLISC 库中,Long
被用来作为矩阵的索引类型。
Llong
是 8 字节整数
Float
是 float
(4 字节浮点数)
Doub
是 double
(8 字节浮点数)
Ldoub
是 long double
(16 字节浮点数,但并不一定是四精度,取决于机器和编译器)
Qdoub
是 16 字节浮点数,标准的四精度(需要在编译时打开 quadmath
选项)。
Fcomp
是 std::complex<float>
(8 字节复数)
Comp
是 std::complex<double>
(16 字节复数)
Lcomp
是 std::complex<long double>
(32 字节复数)
Qcomp
是 std::complex<Qdoub>
32 字节复数,标准的四精度。
另外我们还定义一些附加类型,用于声明函数的参数。例如 Doub_I
是 const Doub
,表示函数的输入参数。又如 Doub_O
是 Doub &
,表示函数的输出参数(原来的值不会被使用)。Doub_IO
也是 Doub &
,但表示既作为输入也作为输出(原来的值会被使用且被覆盖)。以上的标量类型都同理,在后面加 _I
,_O
,_IO
分别表示 in,out,in-out。
以后还会看到矢量类和矩阵类,但和标量不同,为了避免不必要的复制,它们都必须 pass by reference 而不是 pass by value。例如矩阵类 CmatDoub
的 CmatDoub_I
是 const CmatDoub &
,CmatDoub_O
和 CmatDoub_IO
都是 CmatDoub &
。
[1] ^ W. H. Press, et al. Numerical Recipes 3rd edition.
友情链接: 超理论坛 | ©小时科技 保留一切权利