相对于 fortran 或者 Matlab 等,用 C++ 做数值计算的一个缺陷就是语言本身(或标准库)没有矩阵类型(以及高维矩阵类型).但我们可以用第三方库或者自己写一个.本书选择后者,原因是为了教学需要我们需要保持代码的简单易读,避免复杂的 C++ 语法.
本书中我们将大量使用 SLISC 库,即 Scientific Library in Simple C++.代码可以从我们的 GitHub 仓库下载.该库的特点是尽量不使用 C++ 的复杂语法(如模板)和复杂的类结构,使代码便于阅读学习和修改,同时又保持相对较高的性能.SLISC 使用兼容性高得 C++11 标准.
我们希望把矩阵进行一定程度的封装,但又几乎不损失性能.
流行的矩阵库,如 Eigen,但是代码极其复杂,错误信息不容易懂,修改起来非常困难.例如 MatrixXd 矩阵类就有 6 次继承,一个 2x2 的矩阵在 gdb 里面调试的时候显示出来的变量信息是这样的:
<Eigen::PlainObjectBase<Eigen::Matrix<double,-1,-1,0,-1,-1>>> =
{<Eigen::MatrixBase<Eigen::Matrix<double,-1,-1,0,-1,-1>>> =
{<Eigen::DenseBase<Eigen::Matrix<double,-1,-1,0,-1,-1>>> =
{<Eigen::DenseCoeffsBase<Eigen::Matrix<double,-1,-1,0,-1,-1>, 3>> =
{<Eigen::DenseCoeffsBase<Eigen::Matrix<double,-1,-1,0,-1,-1>, 1>> =
{<Eigen::DenseCoeffsBase<Eigen::Matrix<double,-1,-1,0,-1,-1>, 0>> =
{<Eigen::EigenBase<Eigen::Matrix<double,-1,-1,0,-1,-1>>> =
{<No data fields>}, <No data fields>},
<No data fields>}, <No data fields>}, <No data fields>}, <No data fields>},
m_storage = {m_data = 0x855ceb0, m_rows = 2, m_cols = 2}}, <No data fields>
实际上这里面真正有用的只有最后一行,显示了矩阵在内存中的地址 m_data,行数 m_rows 以及列数 m_cols.这样的库只适合直接拿来用,不适合读和改,尤其是对非计算机专业的人来说.
底层用 MKL 来实现,速度非常快.
所有的函数都尽量使用指针 interface(因为是最兼容的!最笨的办法往往是最灵活的)然后可以再封装一层更友好的 interface
slicing 会有少量的 overhead.由用户自己权衡是使用 slicing 还是指针 interface.
在 C++ 标准中,一些基本类型在内存中的长度在不同计算机上可能会不同.例如 long 有时候和 int 一样是 4 字节,而另一些时候则和 long long 一样是 8 字节.因此,SLISC 仿照 Numerical Recipe 的方式,定义自己的类型名称.以后本书统一使用这些定义.
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 字节)
Fcomp 是 std::complex<float>(8 字节)
Comp 是 std::complex<double>(16 字节)
Lcomp 是 std::complex<long double>(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 &.
unsigned 类型.