短:
GNUPlot 比我的 GSL 代码更适合我的数据。为什么?
短的:
我现在有点困惑,所以我的问题可能措辞不是特别好......随着我的理解提高,我会编辑这个。
这个问题的原标题是:“g++ Compiling code with either -o1 -o2 or -o3 flags and floating point precision”
我相信我的代码正遭受数值不稳定的困扰。
GNUPlot 比我的 GSL 代码更适合我的数据,这令人惊讶,因为我相信 GNUPlot 也使用 GSL 库?
长:
我编写了一些使用 GNU 科学库 (GSL) 的 C/C++ 代码。我的代码使非线性函数适合非线性数据集。执行此操作的算法可能对浮点运算发生的顺序高度敏感,这是由于数值不准确性的性质导致数值舍入误差的累积。
问题:“这些可能是由使用优化标志之一运行的效果引起的-o1
,-o2
还是-o3
?”
部分答案:我关闭了所有-oN
标志并重新编译了我的代码,我的结果可能会发生少量变化,即:delta_x / x ~= 1.0e-3
. 与 GNUPlot 相比,拟合度仍然很差。
我适合的功能:
我提供这些是为了向您展示正在发生的数字工作。我怀疑其中一些容易出现数值错误。
的典型值Yi
将在 至 的范围0.0
内1.0
。t
通常在 到 的范围0.0
内200.0
。(但在该范围的前半部分拟合度很差。)
// Block A - Weighted Residuals
double t = time; // whatever that may be
double s = sigma[ix]; // these are the errors, tried 1.0 and 0.001 with no affect on parameter values obtained
double Yi = (std::sqrt(rho) * r0) / std::sqrt((rho - r0*r0) * std::exp(-2.0 * t / tau) + r0*r0); // y value - model
gsl_vector_set(f, ix, (Yi - y[ix])/sigma[ix]); // weighted residual
// Block B - Jacobian
double MEM_A = std::exp(-2.0 * t / tau); // Tried to do some optimization here
double MEM_B = 1.0 - MEM_A; // Perhaps this is causing a problem?
double MEM_C = rho - r0 * r0;
double MEM_D = MEM_C * MEM_A + r0*r0;
double MEM_E = std::pow(MEM_D, 1.5);
double df_drho = (std::pow(r0, 3.0) * MEM_B) / (2.0 * std::sqrt(rho) * MEM_E);
double df_dr0 = (std::pow(rho, 1.5) * MEM_A) / MEM_E;
double df_dtau = -1.0 * (std::sqrt(rho) * r0 * MEM_C * MEM_A * t) / (tau * tau * MEM_E);
gsl_matrix_set(J, ix, 0, df_drho / s);
gsl_matrix_set(J, ix, 1, df_dr0 / s);
gsl_matrix_set(J, ix, 2, df_dtau / s);
这是一个图表,不是很好吗?
好吧,这里有一张图表,它比我用语言更好地解释了这个问题。您可以忽略绿线,它仅显示在运行拟合算法之前给出的初始参数,该算法会更改这些参数。
GNUPlot 拟合结果:
RHOFIT = 0.086173236829715 +- 2.61304934752193e-05
R0FIT = 0.00395856812689133 +- 2.08898744280108e-05
TAUFIT = 11.7694359189233 +- 0.016094629240588
// Not sure how GNUPlot calculates errors - they do not appear to be the regular errors computed from the off diagonal elements of the LM matrix after fitting. (If you know a little about the Levenberg–Marquardt algorithm.)
C++ GSL 拟合结果:
rho = 0.08551510 +/- ...
r0 = 0.00507645 +/- ... // Nonsense errors due to "not-real" errors on data points
tau = 12.99114719 +/- ...
仔细检查后,您会发现粉红色和蓝色线条并没有以相当大的余量相互重叠。粉红线是许多人所说的“合身”。相比之下,蓝线并不是特别好。
我已经尝试使误差条(尽管它们对于所有点的大小都相同——它们不是“真正的”误差条,只是人造的)更小——这没有帮助,只会改变每个点的卡方值和相关错误拟合后的参数。
进一步的随机想法:
- 我建的 GSL 错了吗?
- Gnuplot 将数据集拆分为小块,以使加在一起的数字保持大致相同的数量级?(有点像 FFT 的工作原理。)
GSL 拟合输出:
iter: 0 x = 0.1 0.001 10 |f(x)| = 12487.8
status = success
iter: 1 x = 0.0854247 0.00323946 13.2064 |f(x)| = 10476.9
dx vector: -0.0145753, 0.00223946, 3.20642
status = success
iter: 2 x = 0.0854309 0.00576809 13.7443 |f(x)| = 3670.4
dx vector: 6.18836e-06, 0.00252863, 0.537829
chisq/dof = 6746.03
rho = 0.08543089 +/- 0.00013518
r0 = 0.00576809 +/- 0.00013165
tau = 13.74425294 +/- 0.09012196