我正在研究概率模型,并且在对那些模型进行推论时,估计的概率可能会很小。为了避免下溢,我目前在日志域中工作(我存储概率日志)。乘以概率等效于加法,并且通过使用以下公式来进行求和:
log(exp(a) + exp(b)) = log(exp(a - m) + exp(b - m)) + m
其中
m = max(a, b)
。我使用一些非常大的矩阵,并且必须采用这些矩阵的按元素指数计算矩阵 vector 乘法。此步骤非常昂贵,我想知道在处理概率时是否存在其他方法来处理下溢。
编辑:出于效率原因,我正在寻找使用原始类型而不是存储实数的任意精度表示形式的对象的解决方案。
编辑2:我在寻找比日志域技巧更快的解决方案,而不是更准确的解决方案。我对目前获得的准确性感到满意,但是我需要一种更快的方法。特别是,求和发生在矩阵 vector 乘法过程中,我希望能够使用有效的BLAS方法。
解决方案:与Jonathan Dursi讨论后,我决定按矩阵和 vector 的最大元素分解因数,并将该因数存储在对数域中。乘法很简单。在进行加法运算之前,我必须通过两个因子的比率来分解一个相加的矩阵/vector 。我每十次操作更新一次因子。
最佳答案
最近在computational science stack exchange site上也出现了这个问题,尽管立即担心会发生溢出,但是问题或多或少是相同的。
转换为日志空间无疑是一种合理的方法。无论您处于什么空间,要正确地进行大量求和,可以使用两种方法来提高求和的准确性。补偿求和方法,最著名的是Kahan summation,既保留了总和,又保留了有效的“余数”。它为您提供了使用高精度算术而不带来所有成本(并且仅使用基本类型)的一些优势。其余的术语还可以告诉您您的表现如何。
除了改善加法的实际机制外,更改条件的顺序也可以有很大的不同。对术语进行排序,以便从最小到最大进行求和,这将有所帮助,因为这样您就不再需要频繁地添加非常不同的术语(这可能会导致重大的舍入问题);在某些情况下,对log2 N个重复的成对和进行求和也可以比仅对直线线性求和进行改进,具体取决于您的术语。
所有这些方法的有用性在很大程度上取决于数据的属性。任意精度的数学库在使用计算时间(以及可能的内存)上非常昂贵时,具有作为通用解决方案的优势。
关于java - 如何处理科学计算中的下溢?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/9336701/