所以基本上,我试图计算两件事发生在一起的似然比。 方程式足够直,但问题是我的数据相当大,有时中间操作溢出。
我目前正在使用 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。
答案 0 :(得分:1)
我试过你的表情(因为我不知道 c1 , c2 , c12 和 N的来源我硬编码了他们的价值观)。所以硬编码的值看起来像这样:
double c1 = 0.1;
double c2 = 0.2;
double c12 = 0.3;
double N = 0.4;
我有可能= 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 或溢出的每个值,并手动抛出异常。当您收到无效输入时,这将有助于本地化问题原因。