如何处理科学计算的下溢?

Edo*_*ard 11 java math floating-point scientific-computing

我正在研究概率模型,在对这些模型进行推理时,估计的概率可能变得非常小.为了避免下溢,我目前在日志域工作(我存储概率的日志).乘法概率相当于一个加法,并使用以下公式求和:

log(exp(a) + exp(b)) = log(exp(a - m) + exp(b - m)) + m
Run Code Online (Sandbox Code Playgroud)

哪里m = max(a, b).

我使用了一些非常大的矩阵,我必须采用这些矩阵的元素指数来计算矩阵向量乘法.这一步非常昂贵,我想知道在处理概率时是否存在其他方法来处理下溢.

编辑:出于效率原因,我正在寻找使用原始类型的解决方案,而不是存储实数的任意精度表示的对象.

编辑2:我正在寻找比日志域技巧更快的解决方案,而不是更准确的解决方案.我对目前的准确性感到满意,但我需要一种更快的方法.特别是,在矩阵向量乘法期间进行求和,并且我希望能够使用有效的BLAS方法.

解决方案:在与Jonathan Dursi讨论之后,我决定按其最大元素分解每个矩阵和向量,并将该因子存储在日志域中.乘法很简单.在添加之前,我必须通过两个因子的比率将一个添加的矩阵/向量分解.我每十次操作更新一次因子.

Jon*_*rsi 9

这个问题最近出现在计算科学堆栈交换站点上,尽管存在溢出的直接担忧,但问题或多或少都是一样的.

转换为日志空间当然是一种合理的方法.无论你处于什么样的空间,要正确地完成大量的总和,你可以使用几种方法来提高求和的准确性.补偿求和方法,最着名的是Kahan求和,保持一个总和和实际上是"余数"; 它为您提供了使用更高精度算术的一些优点,而无需所有成本(并且仅使用原始类型).余下的术语也可以告诉你你的表现如何.

除了改进添加的实际机制之外,更改添加术语的顺序可以产生很大的不同.排序你的术语,使你从最小到最大的总和可以帮助,因为你不再经常添加非常不同的术语(这可能导致显着的舍入问题); 在某些情况下,执行log 2 N重复的成对总和也可以比仅执行直线和,这取决于您的术语的样子.

所有这些方法的有用性在很大程度上取决于数据的属性.任意精度数学库虽然在计算时间(以及可能的存储器)中使用非常昂贵,但具有作为相当普遍的解决方案的优点.