当在特征中获得大矩阵的行列式时,避免数值下溢

时间:2013-12-11 20:36:40

标签: c++ floating-point eigen underflow determinants

我使用Eigen库在C ++中实现了MCMC算法。该算法的主要部分是一个循环,其中首先进行一些矩阵计算,然后获得所得矩阵的行列式并将其加到输出中。 E.g:

MatrixXd delta0;
NumericVector out(3);

out[0] = 0;
out[1] = 0;

for (int i = 0; i < s; i++) {
  ...
  delta0 = V*(A.cast<double>()-(A+B).cast<double>()*theta.asDiagonal());
  ...
  I = delta0.determinant()
  out[1] += I;
  out[2] += std::sqrt(I);
}
return out;

现在在某些矩阵上,我不幸地观察到数字下溢,以便将行列式输出为零(实际上不是)。

如何避免此下溢?

一种解决方案是获得行列式的对数而不是行列式。然而,

  • 我不知道该怎么做;
  • 我怎么能把这些日志加起来?

非常感谢任何帮助。

2 个答案:

答案 0 :(得分:3)

我想到了两个主要选项:

  1. 方阵的特征值的乘积是该矩阵的行列式,因此每个特征值的对数之和是该矩阵的行列式的对数。假设det(A) = adet(B) = b为紧凑表示法。在应用上述2个矩阵AB之后,我们最终得到log(a)log(b),然后实际上是以下情况:

    log(a + b) = log(a) + log(1 + e ^ (log(b) - log(a)))
    

    是的,我们得到总和的对数。接下来你会用它做什么?我不知道,取决于你有什么。如果您必须按e ^ log(a + b) = a + b删除对数,那么您可能很幸运a + b的值现在不会下溢,但在某些情况下它仍然可以下溢。

  2. 进行聪明的预处理;这里可能有很多选项,你最好从一些可靠的来源读到它们,因为这是一个严肃的话题。对这个特定问题进行预处理的最简单(也许可能是最便宜)的例子可能是回忆det(c * A) = (c ^ n) * det(A),其中An n矩阵,并且预乘您的矩阵包含一些c,计算行列式,然后将其除以c ^ n以获得实际值。

  3. 更新


    我想了一个选择。如果在#1或#2的最后阶段你仍然经常出现下溢,那么专门为这些最后的操作增加精度可能是个好主意,例如,利用 GNU MPFR

答案 1 :(得分:1)

您可以使用Householder消除来获取delta0的QR分解。那么Q部分的行列式是+/- 1(取决于你是做了偶数还是奇数次的反射),R部分的行列式是对角元素的乘积。这两个都很容易计算,而不会遇到下溢地狱---你可能甚至不关心第一个。