贡献者: addis
相对于 fortran 或者 Matlab 等,用 C++ 做数值计算的一个缺陷就是语言本身(或标准库)没有矩阵以及高维矩阵类。但我们可以用第三方库或者自己写一个。我们选择后者,原因是为了教学需要我们需要保持代码的简单易读,避免复杂的 C++ 语法。
本书中我们将大量使用自编的 SLISC 矩阵库,即 Scientific Library in Simple C++。代码可以从 GitHub 仓库下载。该库的特点是尽量不使用 C++ 的复杂语法(如模板)和复杂的类结构,使代码便于阅读学习和修改,同时又保持相对较高的性能。SLISC 使用兼容性较高的 C++11 标准。
SLISC 库在矩阵类的基础上还实现了一些科学计算常用的功能,如线性代数运算、插值、计时、文件和目录操作、矩阵文件读写、字符串处理、特殊函数、任意精度计算、量子力学计算等。当然,一些功能基于其他开源项目如 Intel MKL,Arb,GSL, Eigen,Arpack。在编译时可以通过宏来决定是否使用这些依赖。
在 SLISC 中,我们希望把矩阵进行一定程度的封装,但又几乎不损失性能。许多人使用流行的矩阵库例如 Eigen,但是其代码复杂,错误信息不容易懂,代码修改起来非常困难。例如 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
。这样的库只适合直接拿来用,不适合阅读、学习和修改,尤其是对非计算机专业的同学来说。
以下列出 SLISC 的一些特性,我们以后会详细介绍。
namespace slisc
,所有宏以 SLS_
开头。
unsigned
类型。
在 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 &
。
 
 
 
 
 
 
 
 
 
 
 
友情链接: 超理论坛 | ©小时科技 保留一切权利