Java 双重溢出
Java Double overflow
基本上,我正在尝试计算同时发生的两件事的似然比。
方程式很直,但问题是我的数据比较大,有时中间运算会溢出。
我目前正在为我的变量使用 double,所以向上转型是不可能的。
该方程还具有 Logarithm 和 exponential 运算符。但是我没有找到 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 我硬编码了他们的值)。所以硬编码值看起来像这样:
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(即使是 "sane-looking" 输入)。
建议将您的长表达式拆分为小的 Java 表达式。并在计算前验证每个可能导致NaN或溢出的值并手动抛出异常。当您收到无效输入时,这将有助于定位问题的原因。
基本上,我正在尝试计算同时发生的两件事的似然比。 方程式很直,但问题是我的数据比较大,有时中间运算会溢出。
我目前正在为我的变量使用 double,所以向上转型是不可能的。
该方程还具有 Logarithm 和 exponential 运算符。但是我没有找到 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 我硬编码了他们的值)。所以硬编码值看起来像这样:
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(即使是 "sane-looking" 输入)。
建议将您的长表达式拆分为小的 Java 表达式。并在计算前验证每个可能导致NaN或溢出的值并手动抛出异常。当您收到无效输入时,这将有助于定位问题的原因。