java - 科学计算中如何处理下溢?

标签 java math floating-point scientific-computing

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

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 进行因式分解,并将该因式存储在对数域中。乘法很简单。在添加之前,我必须通过两个因子的比率对添加的矩阵/vector 之一进行因式分解。我每十次操作更新一次该因子。

最佳答案

这个问题最近出现在 computational science stack exchange site 上也,虽然有直接的担心会溢出,但问题或多或少是一样的。

转化为日志空间当然是一种合理的做法。无论您在哪个空间,要正确地进行大量求和,您可以使用几种方法来提高求和的准确性。补偿求和方法,最著名的是 Kahan summation ,同时保留总和和有效的“余数”;它为您提供了使用更高精度算术的一些优势,而无需所有成本(并且仅使用原始类型)。余项还可以让您了解自己的表现。

除了改进添加项的实际机制之外,更改添加项的顺序也会产生很大的不同。对术语进行排序,以便从最小到最大求和会有所帮助,因为这样您就不会再频繁地添加差异很大的术语(这可能会导致严重的舍入问题);在某些情况下,进行 log2 N 次重复的成对求和也可以比仅进行线性求和有所改进,具体取决于您的术语。

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

关于java - 科学计算中如何处理下溢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9336701/

相关文章:

php - 如何用编程语言求解数学方程式?

c++ - 在 C++ 中使用 std::istringsteam 将字符串转换为 float

c - 禁用 SSE 的 SSE 寄存器返回

java - SBT scala 猴子补丁库

Java Spring MVC 使用拦截器转发/重定向 POST 请求

java - 初学者在 Java 中编写完成正方形时遇到困难

java - 确定 2 个直角棱镜是否接触/相交

javascript - 我如何在 webgl 中使用 stride?

java - 如果方法的参数是先前设置的变量而不是直接输入,为什么该方法会返回不同的值?

java - 无法在 openGL 中渲染形状