我已经阅读了这篇文章NUM00-J。检测或防止整数溢出和这个问题Java如何处理整数下溢和溢出以及如何检查它?
可以看到,当一个整数乘以另一个整数时,有许多解决方案可以防止整数溢出。但我想知道是否有任何解决方案,以防止整数溢出时乘以浮点数?
我当前的(愚蠢的)解决方案:
public static final int mulInt(int a, float b) {
double c = a * b;
return c > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int)c;
}
但是它有很多问题:
- 执行乘法运算可以得到预期的结果两个参数都必须是小数值的乘法。
- 当参数是大型数字结果是必然不正确(我知道部分原因是因为浮点数据类型)。
- 假设如果计算结果大于最大值加倍,它将不可阻挡地返回a负数。
那么,这个问题的真正解决方案是什么呢?
你的回答会很有帮助,我会很感激的!
更新:这里有另一个问题,我如何检查两个数字在Java中相乘是否会导致溢出?这是非常相似的,但它是用一个整数乘以一个整数,而不是乘以一个浮点数。
下面是一个可能对Java有启发的C方法。
在赋值前使用double
而不是float
math执行乘法运算,以获得double
的额外精度/范围。
像c > Integer.MAX_VALUE
这样的比较,Integer.MAX_VALUE
首先被转换成double
。这可能会失去精确性。*1考虑如果转换值是Integer.MAX_VALUE + 1.0
会发生什么。然后,如果c
是Integer.MAX_VALUE + 1.0
,代码将尝试返回(int) (Integer.MAX_VALUE + 1.0)
-不好。最好使用格式良好的极限。(也有负面的。)在C语言(可能是Java)中,到int
的浮点转换会截断分数。在边缘处需要特别小心。
#define INT_MAX_PLUS1_AS_DOUBLE ((INT_MAX/2 + 1)*2.0)
int mulInt(int a, float b) {
// double c = a * b;
double c = (double) a * b;
//return c > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int)c;
if (c < INT_MAX_PLUS1_AS_DOUBLE && c - INT_MIN > -1.0) {
return (int) c;
}
if (c > 0) return INT_MAX;
if (c < 0) return INT_MIN;
return 0; // `b` was a NaN
}
c - INT_MIN > -1
类似于c > INT_MIN - 1
,但由于INT_MIN
是-2的幂,INT_MIN - 1
可能不能精确地转换为double
。c - INT_MIN
应该精确地接近边缘情况。
*1当int
为32位(或更少)而double
为64位(具有53位有效)时没有问题。但重要的与更大范围的整数类型。