Java 浮点型和双精度数据类型的上溢和下溢
Overflow and Underflow in Java Float and Double Data Types
我创建了以下代码来测试下溢和上溢的 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("");
谁能解释一下我在结果中看到的奇怪值:
当我用 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("");
结果符合预期:
有人可以解释 Java float 和 double 中的上溢和下溢吗?为什么我会看到上面的结果?
这些 "weird" 结果并非真正特定于 Java。只是相关 IEEE 标准定义的浮点数比大多数人怀疑的要复杂得多。但是根据您的具体结果:Float.MIN_VALUE
是最小的 positive 浮点数,因此它非常接近 0。因此 Float.MIN_VALUE - 1
将非常接近 -1。但由于 -1 附近的浮点精度大于该差值,因此结果为 -1。至于Float.MAX_VALUE
,这个值的浮点数精度远大于1,加一不会改变结果。
浮点溢出
将 1
添加到 Double.MAX_VALUE
或 Float.MAX_VALUE
所代表的值不足以避免由于精度错误而向下舍入。在Double.MAX_VALUE
处,difference between consecutive values,由于尾数有53位,相当大。
System.out.println("Math.ulp(Double.MAX_VALUE) is " + Math.ulp(Double.MAX_VALUE));
1.9958403095347198E292
这个值为2971.
您需要添加一个至少产生这么多溢出到 Infinity
的表达式。我说 "yields at least this much" 是因为我可以通过添加 2970 使它溢出,但是 2969 没有效果。
doubleTest += Math.pow(2.0, 969);
1.7976931348623157E308
和
doubleTest += Math.pow(2.0, 970);
Infinity
看起来 2970 被四舍五入到 2971 以添加到 Double.MAX_VALUE
,但是 2969 向下舍入为 0
并且对总和没有影响。
float
也发生了类似的过程,但值并没有那么高。
浮点数下溢
doubleTest = Double.MIN_VALUE;
doubleTest--;
这只是一个无穷小的值减一,实际上是负一。这不是下溢。
当 指数 (而非值)变得太低而无法表示时,会发生下溢,因此会产生 0.0
。除以 2
而不是得到下溢。
doubleTest = Double.MIN_VALUE;
doubleTest /= 2;
0.0
Integer/Long Overflow/Underflow
这些是预期值,因为您知道值范围另一端的值 "wrap around"。
你的结果不一定与众不同,只是一般的花车都非常具体,你的要求非常接近。我在使用双数据类型时遇到过类似的问题。只需仔细检查以确保您的代码符合您的预期。
我创建了以下代码来测试下溢和上溢的 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("");
谁能解释一下我在结果中看到的奇怪值:
当我用 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("");
结果符合预期:
有人可以解释 Java float 和 double 中的上溢和下溢吗?为什么我会看到上面的结果?
这些 "weird" 结果并非真正特定于 Java。只是相关 IEEE 标准定义的浮点数比大多数人怀疑的要复杂得多。但是根据您的具体结果:Float.MIN_VALUE
是最小的 positive 浮点数,因此它非常接近 0。因此 Float.MIN_VALUE - 1
将非常接近 -1。但由于 -1 附近的浮点精度大于该差值,因此结果为 -1。至于Float.MAX_VALUE
,这个值的浮点数精度远大于1,加一不会改变结果。
浮点溢出
将 1
添加到 Double.MAX_VALUE
或 Float.MAX_VALUE
所代表的值不足以避免由于精度错误而向下舍入。在Double.MAX_VALUE
处,difference between consecutive values,由于尾数有53位,相当大。
System.out.println("Math.ulp(Double.MAX_VALUE) is " + Math.ulp(Double.MAX_VALUE));
1.9958403095347198E292
这个值为2971.
您需要添加一个至少产生这么多溢出到 Infinity
的表达式。我说 "yields at least this much" 是因为我可以通过添加 2970 使它溢出,但是 2969 没有效果。
doubleTest += Math.pow(2.0, 969);
1.7976931348623157E308
和
doubleTest += Math.pow(2.0, 970);
Infinity
看起来 2970 被四舍五入到 2971 以添加到 Double.MAX_VALUE
,但是 2969 向下舍入为 0
并且对总和没有影响。
float
也发生了类似的过程,但值并没有那么高。
浮点数下溢
doubleTest = Double.MIN_VALUE;
doubleTest--;
这只是一个无穷小的值减一,实际上是负一。这不是下溢。
当 指数 (而非值)变得太低而无法表示时,会发生下溢,因此会产生 0.0
。除以 2
而不是得到下溢。
doubleTest = Double.MIN_VALUE;
doubleTest /= 2;
0.0
Integer/Long Overflow/Underflow
这些是预期值,因为您知道值范围另一端的值 "wrap around"。
你的结果不一定与众不同,只是一般的花车都非常具体,你的要求非常接近。我在使用双数据类型时遇到过类似的问题。只需仔细检查以确保您的代码符合您的预期。