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

时间:2012-02-17 23:06:53

标签: java math floating-point scientific-computing

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

log(exp(a) + exp(b)) = log(exp(a - m) + exp(b - m)) + m

其中m = max(a, b)

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

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

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

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

5 个答案:

答案 0 :(得分:9)

最近在computational science stack exchange site上出现了这个问题,虽然立即担心会出现溢出,但问题或多或少都是一样的。

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

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

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

答案 1 :(得分:4)

选项1: Commons Math - The Apache Commons Mathematics Library

  

Commons Math是一个轻量级,自包含的数学和统计组件库,可解决最常见的问题   可以使用Java编程语言或Commons Lang。

注意:API在命名工厂DfpField(而不是更直观的DfpFac或DfpFactory)时保护构造函数强制工厂模式。所以你必须使用

new DfpField(numberOfDigits).newDfp(myNormalNumber)

实例化一个Dfp,然后你可以调用.multiply或其他任何东西。我以为我会提到这个,因为它有点令人困惑。

选项2: GNU Scientific LibraryBoost C++ Libraries。 在这些情况下,您应该使用JNI来调用这些本机库。

选项3 :如果您可以自由使用其他程序和/或语言,则可以考虑使用程序/语言进行数值计算,例如OctaveScilab,和类似的。

选项4: BigDecimal Java。

答案 2 :(得分:4)

几年前我遇到了类似的问题。解决方案是开发log(1 + exp(-x))的近似值。近似的范围不需要那么大(x从0到40就足够了),至少在我的情况下,准确度也不需要特别高。

在您的情况下,看起来您需要计算log(1 + exp(-x1)+ exp(-x2)+ ...)。抛弃那些大的负值。例如,假设a,b和c是三个对数概率,其中0> a> b> c。如果a-c> 38,则可以忽略c。它根本不会对你的联合记录概率有所贡献,至少在你使用双打时不会有所贡献。

答案 3 :(得分:1)

我认为你可能最好使用与double相同的概念,即浮点表示,而不是以对数形式存储值。例如,您可以将每个值存储为两个long s,一个用于符号和尾数,一个用于指数。 ( Real 浮点有一个经过精心调整的设计,可以支持大量的边缘情况并避免浪费一点;但你可能不需要担心任何这些,并且可以专注于以一种易于实现的方式进行设计。)

答案 4 :(得分:0)

我不明白为什么会这样,但这个公式似乎有效并且更简单:

c = a + log(1 + exp(b - a))

c = log(exp(a)+exp(b))