Java Float和双数据类型中的溢出和下溢

时间:2018-01-22 18:57:43

标签: java overflow underflow

我创建了以下代码来测试Float和Double Java数值数据类型的下溢和溢出:

// Float Overflow & Underflow
float floatTest = Float.MAX_VALUE;
floatTest++;
out.println("Float Overflow: " + Float.MAX_VALUE + " + 1 = " + floatTest);
floatTest = Float.MIN_VALUE;
floatTest--;
out.println("Float Underflow: " + Float.MIN_VALUE + " - 1 = " + floatTest);
out.println("");

// Double Overflow & Underflow
double doubleTest = Double.MAX_VALUE;
doubleTest++;
out.println("Double Overflow: " + Double.MAX_VALUE + " + 1 = " + doubleTest);
doubleTest = Double.MIN_VALUE;
doubleTest--;
out.println("Double Underflow: " + Double.MIN_VALUE + " - 1 = " + doubleTest);
out.println("");

有人可以解释我在结果中看到的奇怪值: enter image description here

当我使用byte,short,int和long进行类似测试(下面的代码)时:

// BYTE Overflow & Underflow
byte byteTest = Byte.MAX_VALUE;
byteTest++;
out.println("Byte Overflow: " + Byte.MAX_VALUE + " + 1 = " + byteTest);
byteTest = Byte.MIN_VALUE;
byteTest--;
out.println("Byte Underflow: " + Byte.MIN_VALUE + " - 1 = " + byteTest);
out.println("");

// SHORT Overflow & Underflow
short shortTest = Short.MAX_VALUE;
shortTest++;
out.println("Short Overflow: " + Short.MAX_VALUE + " + 1 = " + shortTest);
shortTest = Short.MIN_VALUE;
shortTest--;
out.println("Short Underflow: " + Short.MIN_VALUE + " - 1 = " + shortTest);
out.println("");

// INTEGER Overflow & Underflow
int intTest = Integer.MAX_VALUE;
intTest++;
out.println("Integer Overflow: " + Integer.MAX_VALUE + " + 1 = " + intTest);
intTest = Integer.MIN_VALUE;
intTest--;
out.println("Integer Underflow: " + Integer.MIN_VALUE + " - 1 = " + intTest);
out.println("");

// LONG Overflow & Underflow
long longTest = Long.MAX_VALUE;
longTest++;
out.println("Long Overflow: " + Long.MAX_VALUE + " + 1 = " + longTest);
longTest = Long.MIN_VALUE;
longTest--;
out.println("Long Underflow: " + Long.MIN_VALUE + " - 1 = " + longTest);
out.println("");

结果看起来像预期的那样:

enter image description here

有人可以解释Java float和double中的溢出和下溢,为什么我看到上面的结果?

3 个答案:

答案 0 :(得分:4)

浮点溢出

1添加到Double.MAX_VALUEFloat.MAX_VALUE并不代表足够的值,以避免由于精度错误而向下舍入。在Double.MAX_VALUE,由于尾数为53位,difference between consecutive values非常大。

System.out.println("Math.ulp(Double.MAX_VALUE) is " + Math.ulp(Double.MAX_VALUE));

1.9958403095347198E292

该值为2 971

你需要添加一个至少产生这么多的表达式来溢出到Infinity。我说"收益至少这么多"因为我可以通过添加2 970 来使其溢出,但是2 969 没有效果。

doubleTest += Math.pow(2.0, 969);

1.7976931348623157E308

doubleTest += Math.pow(2.0, 970);

Infinity

看起来2 970 被舍入到2 971 被添加到Double.MAX_VALUE,但是2 969 被舍入降至0并且对总和没有影响。

float正在发生类似的过程,但价值并不高。

浮点下溢

doubleTest = Double.MIN_VALUE;
doubleTest--;

这只是一个无穷小的值减1,实际上是减1。这不是下流。

指数而不是值太低而无法表示时,会发生下溢,因此会产生0.0。除以2代替以获得下溢。

doubleTest = Double.MIN_VALUE;
doubleTest /= 2;

0.0

整数/长溢出/下溢

这些是预期值,因为您知道值"环绕"到价值范围的另一边。

答案 1 :(得分:3)

这些“怪异”的结果并不是特定于Java的。只是相关IEEE标准定义的浮动,比大多数人怀疑的要复杂得多。但是根据您的具体结果:Float.MIN_VALUE是最小的浮点数,因此它非常接近0.因此Float.MIN_VALUE - 1将非常接近-1。但是由于-1的浮点精度大于该差值,因此它以-1表示。对于Float.MAX_VALUE,此值周围的浮点精度远大于1,并且添加一个不会更改结果。

答案 2 :(得分:0)

你的结果不一定与众不同,只是浮动通常是非常具体的,你的要求非常接近。我在使用双数据类型时遇到了类似的问题。只需仔细检查一下,确保您的代码检查出您的期望。