【发布时间】:2021-04-18 20:38:41
【问题描述】:
只要能量变量(双精度类型)没有收敛到某个阈值以下,我就有一个 while 循环。计算此能量所需的变量之一是双精度的犰狳矩阵,名为 f_mo。在while循环中,这个f_mo迭代更新,所以我在每个循环开始时计算f_mo为:
arma::mat f_mo = h_core_mo;//h_core_mo is an Armadillo matrix of doubles
for(size_t p = 0; p < n_mo; p++) {//n_mo is of type size_t
for(size_t q = 0; q < n_mo; q++) {
double sum = 0.0;
for(size_t i = 0; i < n_occ; i++) {//n_occ is of type size_t
//f_mo(p,q) += 2.0*g_mat_full_qp1_qp1_mo(p*n_mo + q, i*n_mo + i)-g_mat_full_qp1_qp1_mo(p*n_mo+i,i*n_mo+q); //all g_mat_ are Armadillo matrices of doubles
sum += 2.0*g_mat_full_qp1_qp1_mo(p*n_mo + q, i*n_mo + i)-g_mat_full_qp1_qp1_mo(p*n_mo+i,i*n_mo+q);
}
for(size_t i2 = 0; i2 < n_occ2; i2++) {//n_occ2 is of type size_t
//f_mo(p,q) -= 1.0*g_mat_full_qp1_qp2_mo(p*n_mo + q, i2*n_mo2 + i2);
sum -= 1.0*g_mat_full_qp1_qp2_mo(p*n_mo + q, i2*n_mo2 + i2);
}
f_mo(p,q) +=sum;
}}
但是假设我直接将总和(我在 f_mo(p,q) 的末尾添加)替换为 f_mo(p,q) 的添加(注释掉的代码)。输出 f_mo 矩阵与机器精度相同。有关代码的任何内容都不应更改。循环中唯一受影响的变量是 sum 和 f_mo。然而,代码会收敛到不同的能量,并且会在非常不同的 while 循环迭代次数中收敛。我不知道差异的原因。当我运行相同的代码 2、3、4、5 次时,每次都会得到相同的结果。当我在没有优化的情况下重新编译时,我遇到了同样的问题。当我在另一台计算机上运行(控制环境)时,尽管 f_mo 相同,但我再次在 # of while 循环中发现差异,但每种方法的迭代总数(sum += 和 f_mo(p,q) += ) 不同。
值得注意的是,代码输出不同的点始终是g_mat_full_qp1_qp2_mo,稍后在while循环中重新计算。但是,进入 g_mat_full_qp1_qp2_mo 计算的每个变量在两个代码之间都是相同的。这使我认为 C++ 有一些我不理解的更深刻的东西。我欢迎任何关于如何继续调试此行为的想法(我几乎可以肯定这不是一个典型的错误,并且我已经控制了环境和优化)
【问题讨论】:
-
这可能是一个精度错误。
sum从零开始,因此将小幅度数字添加到 0 将保持完整精度。因为f_mo(p,q)中有一个值,所以添加小幅度数字可能会导致精度损失,因为较低精度的位会丢失。见this question。 -
@1201ProgramAlarm 谢谢你的提示。我应该补充一点,能量值不同的第一次迭代,它们在 10^-10 的数量级上不同(并且在上一次迭代中它们匹配到 10^-50)。如果我的解释有误,请纠正我,但因此在我看来这不太可能是由精度错误引起的。
-
没有您的代码和minimal reproducible example,只能推测原因。
标签: c++ debugging precision armadillo