Java 双重溢出

Java Double overflow

基本上,我正在尝试计算同时发生的两件事的似然比。 方程式很直,但问题是我的数据比较大,有时中间运算会溢出。

我目前正在为我的变量使用 double,所以向上转型是不可能的。
该方程还具有 Logarithmexponential 运算符。但是我没有找到 BigDecimal 或类似类型的任何非基本数学函数。

此外,我已经尝试过尽可能简化方程式。

我想知道我在这里有什么选择。这是我的代码:

    c1 = unigramsInfo.get(w1)[0];
    c2 = unigramsInfo.get(w2)[0];
    c12 = entry.getValue()[0];
    N = additionalInfo.get("tail")[1];

    p = c2 / N;
    p1 = c12 / c1;
    p2 = (c2 - c12) / (N - c1);

likelihood = - 2 * ( c2 * Math.log(p) + (N - c2) * Math.log(1 - p)
             - c12 * Math.log(p1) - (c1 - c12) * Math.log(1 - p1)
             - (c2 - c12) * Math.log(p2) 
             - (N - c1 - c2 - c12) * Math.log(1 - p2) );

这里的N大到千万,小到1.0E-7的概率。

我试过你的表达方式(因为我不知道 c1c2 的来源c12N 我硬编码了他们的值)。所以硬编码值看起来像这样:

double c1 = 0.1;
double c2 = 0.2;
double c12 = 0.3;
double N = 0.4;

而且我有 likelihood=NaN.

如上评论所述,注意输入。第一个有问题的表达式是(由于除以额外的小数或大数,您可能会在此处溢出):

double p = c2 / N;
double p1 = c12 / c1;
double p2 = (c2 - c12) / (N - c1);

然后你计算对数。实际上在我的例子中(使用上面列出的硬编码值)我在 Math.log(1 - p1) 表达式中得到 NaN (因为它试图计算负数的十进制对数 - p1 < 1c1 > c2 - 非常可能的情况)。

一般来说,您不仅可以得到溢出(在极端情况下),还可以得到 NaN(即使是 "sane-looking" 输入)。

建议将您的长表达式拆分为小的 Java 表达式。并在计算前验证每个可能导致NaN或溢出的值并手动抛出异常。当您收到无效输入时,这将有助于定位问题的原因。