基本上,我正在尝试计算同时发生的两件事的似然比。 方程式足够直接,但问题是我的数据相当大,有时中间操作会溢出。
我目前正在为我的变量使用double,所以向上转型是不可能的。
该方程还具有对数 和指数 运算符。但是,我没有找到 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。
最佳答案
我试过你的表达方式(因为我不知道 c1、c2、c12 和 N 的来源 我硬编码了他们的值(value)观)。所以硬编码值看起来像这样:
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 < 1 当 c1 > c2 - 非常可能的情况)。
一般来说,您不仅会出现溢出(在极端情况下),还会出现 NaN(即使是“看起来很正常”的输入)。
建议将长表达式拆分为小的 Java 表达式。并在计算前验证每个可能导致NaN或溢出的值,并手动抛出异常。当您收到无效输入时,这将有助于定位问题的原因。
关于Java 双重溢出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33619725/