贡献者: addis
Matlab 和 Python 等动态语言虽然用起来方便,但缺点是运行较慢,对于一些计算量大的项目不适合。目前在高性能计算中广泛使用的只有两种语言即 C++ 和 Fortran。虽然 Fortran 普遍被认为是一个过时的语言,但在计算物理中,许多人仍然在使用,一是因为以前遗留下的 Fortran 代码比较多,二是一些年纪较大的学者只会 Fortran。
一本在数值算法中很有名的书是 Numerical Recipes,这本书第三版以前都使用 Fortran 或 C,而第三版却只有 C++,这也是本部分选择介绍 C++ 而不是 Fortran 的原因之一。本部分将从 Numerical Recipes 中借鉴许多代码上的风格和算法。
C++ 的特征实在多不胜数,事实上无论是什么语言,做计算物理的研究者大多会倾向于只选择一些最基础的语法来使用。我们在这里列出本部分使用的 C++ 特性。
在学习基本 C++ 语法时,强烈建议在 Jupyter Notebook 中使用 cling 解释器。这将节约大量的编译时间。
bool, char, int, long, long long, float, double,long double)char, short, int 几乎总是 8, 16, 32 bit 的,虽然标准没这么规定。
=, +, -, *, /, %, ++, --, +=, -=, *=, /=, ?:) 以及优先级
f1() + f2() + f3() 等效于 (f1() + f2()) + f3(),但是三个函数被调用的顺序是没有定义的。
% 的定义使 (m / n) * n + m % n == m 成立。
&, |, ^, ~, <<,>>)
printf, cout)
if, else if, else)
for(;;), while,do while,break,continue)
goto,label: 几乎不使用。
inline 函数,static 变量,pass by value/reference)
const
#include <> 和 "" 的区别
typedef
new, delete。
throw, try, catch,std::runtime_error,out_of_range 等。
static_cast<新类型>(变量) 和 (新类型)变量 效果相同,但有一些转换不允许。
reinterpret_cast<新类型*>(变量指针) 和 reinterpret_cast<新类型&>(变量) 并不会检查 strict aliasing rule,需要用户自己保证。
char* 和 (un)signed char* 指向任何地址,用 base type 的指针指向对象等。
cmath
complex
vector(包括内存管理机制、改变长度可能使指针失效)
string, u32string
iostream(cin,cout,<< 算符,>> 算符,cin 可以放在判断语句中,如 if (cin >> a)。)
ifstream,ofstream
cin 或 fin 读到了文件末尾(文件末尾允许任意多空格/空行)?不要用 cin.eof 判断,例如读 int,可以先初始化为 INT_MAX,然后读完以后判断是否仍为 INT_MAX。
cin.ignore(numeric_limits<int>::max(), '\n');
#include <climits> 中的常数(INT_MIN,INT_MAX,DBL_MAX,DBL_EPSILON),以及 std::numeric_limits<>::max() 等。
unordered_set, set, unordered_map, map, list, dequeue, stack 等。
__cplusplus 用于检测 cpp 版本。
<bits/stdc++.h> 快速 include 所有 C 头文件和 STL 头文件。
pair
unordered_set,set
unordered_map,ordered_map
stack
queue,deque,priority_que
for(auto &e : v),需要定义 v.begin(),v.end(),iterator 需要支持 ++,!=,*p。
public, private,数据成员,函数成员,operator+, -, *, /, (), [])
类名() = default;(可以有其他 constructor),没有 destructor,没有 virtual function。可以用 std::is_pod<类名>::value 来判断。
#include, #define, #if, #ifdef, #ifndef, #else, #endif)
var(变量),#var(字符串),以及 ...##... 用于连接变量1。
#define ... do {} while(0) 避免多个语句不加花括号带来的错误。
namespace
constexpr
decltype(double x; decltype(x) y;)
[=] [&]
extern "C" 参考
#ifdef __cplusplus 用于判断是否在用 C++ 编译器,还可以判断版本:#if __cplusplus >= 201103L,201402L,201703L
1. ^ 例如 #define MYFUN1(x) x*x,那么 MYFUN1(abcd) 就展开为 abcd*abcd。#define MYFUN2(x) #x,那么 MYFUN2(abcd) 就展开为 "abcd"。#define MYFUN3(x,y) a##x##y##f,那么 MYFUN3(bc,de) 展开为 abcdef。注意作为宏函数自变量的宏名不会先展开,例如 #define NUM 5,那么 MYFUN1(NUM) 先展开为 NUM*NUM 再进一步展开为 5*5。又例如 MYFUN2(NUM) 会展开为 "NUM",但字符串不会作为宏进一步展开。宏函数体中双引号内的东西都不会展开,例如 #define MYFUN4(x) "x",那么 MYFUN4(abc) 仍然展开为 "x"