从实数拓展到复数的代码修改基本完成
五一假期前,我在尝试使我的伽辽金边界元数值算法库仅基于已有的一套代码而无需重写,就能从实数拓展到复数,从而不光能够求解静态问题,也能求解时谐的波动问题(亥姆霍兹方程,包括标量的声波方程与矢量的高频电磁场方程),从而具有更大的实用价值。在这个过程中,我发现 C++ 标准库中的复数类型 std::complex
无法从 CPU host 跨越至 CUDA device ,从而导致大量的编译错误。
五一假期中,我重新理清了思路,通过定义 alias template ,能够确保在 host 与 device 上自动地分别使用两种不同但是数据内存排布完全一致的复数类型。这种对于数据类型的区分(demarcation),使得凡是进入到 kernel 与 device 函数的数据结构(主要是模板类)能够使用我自己定义的复数类。这一思路在原理上是完全行得通的。接来下,我便重新浏览层层调用的函数,修改其模板参数与函数参数类型。基本上在假期结束前完成了代码的修改。
编译上述刚改好的版本,依旧是报出大量的错误。根源在于我所用到的第三方线性代数库尚不支持复数运算。对于这个问题,技术路线很明确,只能通过编写自己的大型线性代数方程组迭代求解器予以解决。于是,接下来就是复习博士研究生一年级时选修的面向工科学生的高等数值分析课程。重温了理论后,就可以绕过第三方库的复杂设计,着手实现自己的简单、清晰且通用(适用于实数与复数)的版本。
有了自己的通用求解器作为替代,再修改了一些 C++ 语法上的小疏漏,上述编译错误就完全消除了。由于此次的代码修改仅涉及数据类型的自动区分,而与具体的算法逻辑无关,因此,可以有很大程度的信心能够保证重现之前的测试结果,即在纯实数运算的情况下,所有测试用例都能够成功通过。
体会有二:
- 面对大量编译器错误,眼光不能仅局限于错误提示本身——更何况由 C++ 模板代码产生的错误信息基本上如同天书,难以且没有必要去逐一研读——而要去理解与把握导致问题的根源。然后,围绕这个问题的根源动脑筋、提出解决方案。这样的方案并非头痛医头、脚痛医脚的治标办法,而是具有原则性与导向性,且如同快刀斩乱麻一般地有效。
- 在大量修改代码的过程中,对于自己改了什么、未改什么,要有宏观且清晰的把握。这样,我们对于代码编译与测试中可能出现什么样的问题就有一个基本预判和应有的信心。