You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by te...@apache.org on 2007/06/14 12:59:09 UTC
svn commit: r547215 - in
/harmony/enhanced/classlib/branches/java6/modules/luni/src:
main/java/java/lang/Math.java
test/java/org/apache/harmony/luni/tests/java/lang/MathTest.java
Author: tellison
Date: Thu Jun 14 03:59:09 2007
New Revision: 547215
URL: http://svn.apache.org/viewvc?view=rev&rev=547215
Log:
Apply patch HARMONY-4151 ([classlib][luni][java6] new methods scalb in java.lang.Math)
Modified:
harmony/enhanced/classlib/branches/java6/modules/luni/src/main/java/java/lang/Math.java
harmony/enhanced/classlib/branches/java6/modules/luni/src/test/java/org/apache/harmony/luni/tests/java/lang/MathTest.java
Modified: harmony/enhanced/classlib/branches/java6/modules/luni/src/main/java/java/lang/Math.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/branches/java6/modules/luni/src/main/java/java/lang/Math.java?view=diff&rev=547215&r1=547214&r2=547215
==============================================================================
--- harmony/enhanced/classlib/branches/java6/modules/luni/src/main/java/java/lang/Math.java (original)
+++ harmony/enhanced/classlib/branches/java6/modules/luni/src/main/java/java/lang/Math.java Thu Jun 14 03:59:09 2007
@@ -28,16 +28,24 @@
private static final int FLOAT_EXPONENT_MASK = 0x7F800000;
+ private static final int DOUBLE_NON_MANTISSA_BITS = 12;
+
private static final int DOUBLE_MANTISSA_BITS = 52;
-
+
+ private static final int FLOAT_NON_MANTISSA_BITS = 9;
+
private static final int FLOAT_MANTISSA_BITS = 23;
private static final int DOUBLE_EXPONENT_BIAS = 1023;
- private static final long DOUBLE_EXPONENT_MASK = 0x7fff000000000000L;
-
+ private static final long DOUBLE_EXPONENT_MASK = 0x7ff0000000000000L;
+
+ private static final int FLOAT_MANTISSA_MASK = 0x007fffff;
+
private static final int FLOAT_SIGN_MASK = 0x80000000;
-
+
+ private static final long DOUBLE_MANTISSA_MASK = 0x000fffffffffffffL;
+
private static final long DOUBLE_SIGN_MASK = 0x8000000000000000L;
/**
@@ -838,5 +846,184 @@
} else {
return Float.intBitsToFloat(Float.floatToIntBits(f) - 1);
}
+ }
+
+ /**
+ * Answers a double value of d * 2^scaleFactor, the result may be rounded.
+ *
+ * @param d
+ * the base number
+ * @param scaleFactor
+ * the power number
+ * @return d * 2^scaleFactor
+ *
+ * @since 1.6
+ */
+ @SuppressWarnings("boxing")
+ public static double scalb(double d, int scaleFactor) {
+ if (Double.isNaN(d) || Double.isInfinite(d) || 0 == d) {
+ return d;
+ }
+ // change double to long for calculation
+ long bits = Double.doubleToLongBits(d);
+ // the sign of the results must be the same of given d
+ long sign = bits & DOUBLE_SIGN_MASK;
+ // calculates the factor of the result
+ long factor = ((bits & DOUBLE_EXPONENT_MASK) >> DOUBLE_MANTISSA_BITS)
+ - DOUBLE_EXPONENT_BIAS + scaleFactor;
+
+ // calcutes the factor of sub-normal values
+ int subNormalFactor = Long.numberOfLeadingZeros(bits
+ & ~DOUBLE_SIGN_MASK)
+ - DOUBLE_NON_MANTISSA_BITS;
+ if (subNormalFactor < 0) {
+ // not sub-normal values
+ subNormalFactor = 0;
+ } else {
+ factor = factor - subNormalFactor;
+ }
+ if (factor > Double.MAX_EXPONENT) {
+ return (d > 0 ? Double.POSITIVE_INFINITY : Double.NEGATIVE_INFINITY);
+ }
+
+ long result;
+ // if result is a sub-normal
+ if (factor <= -DOUBLE_EXPONENT_BIAS) {
+ // the number of digits that shifts
+ long digits = factor + DOUBLE_EXPONENT_BIAS + subNormalFactor;
+ if (Math.abs(d) < Double.MIN_NORMAL) {
+ // origin d is already sub-normal
+ result = shiftLongBits(bits & DOUBLE_MANTISSA_MASK, digits);
+ } else {
+ // origin d is not sub-normal, change mantissa to sub-normal
+ result = shiftLongBits(bits & DOUBLE_MANTISSA_MASK
+ | 0x0010000000000000L, digits - 1);
+ }
+ } else {
+ if (Math.abs(d) >= Double.MIN_NORMAL) {
+ // common situation
+ result = ((factor + DOUBLE_EXPONENT_BIAS) << DOUBLE_MANTISSA_BITS)
+ | (bits & DOUBLE_MANTISSA_MASK);
+ } else {
+ // origin d is sub-normal, change mantissa to normal style
+ result = ((factor + DOUBLE_EXPONENT_BIAS) << DOUBLE_MANTISSA_BITS)
+ | ((bits << (subNormalFactor + 1)) & DOUBLE_MANTISSA_MASK);
+ }
+ }
+ return Double.longBitsToDouble(result | sign);
+ }
+
+ /**
+ * Answers a float value of d * 2^scaleFactor, the result may be rounded.
+ *
+ * @param d
+ * the base number
+ * @param scaleFactor
+ * the power number
+ * @return d * 2^scaleFactor
+ *
+ * @since 1.6
+ */
+ public static float scalb(float d, int scaleFactor) {
+ if (Float.isNaN(d) || Float.isInfinite(d) || 0 == d) {
+ return d;
+ }
+ int bits = Float.floatToIntBits(d);
+ int sign = bits & FLOAT_SIGN_MASK;
+ int factor = ((bits & FLOAT_EXPONENT_MASK) >> FLOAT_MANTISSA_BITS)
+ - FLOAT_EXPONENT_BIAS + scaleFactor;
+ // calcutes the factor of sub-normal values
+ int subNormalFactor = Integer.numberOfLeadingZeros(bits
+ & ~FLOAT_SIGN_MASK)
+ - FLOAT_NON_MANTISSA_BITS;
+ if (subNormalFactor < 0) {
+ // not sub-normal values
+ subNormalFactor = 0;
+ } else {
+ factor = factor - subNormalFactor;
+ }
+ if (factor > Float.MAX_EXPONENT) {
+ return (d > 0 ? Float.POSITIVE_INFINITY : Float.NEGATIVE_INFINITY);
+ }
+
+ int result;
+ // if result is a sub-normal
+ if (factor <= -FLOAT_EXPONENT_BIAS) {
+ // the number of digits that shifts
+ int digits = factor + FLOAT_EXPONENT_BIAS + subNormalFactor;
+ if (Math.abs(d) < Float.MIN_NORMAL) {
+ // origin d is already sub-normal
+ result = shiftIntBits(bits & FLOAT_MANTISSA_MASK, digits);
+ } else {
+ // origin d is not sub-normal, change mantissa to sub-normal
+ result = shiftIntBits(bits & FLOAT_MANTISSA_MASK | 0x00800000,
+ digits - 1);
+ }
+ } else {
+ if (Math.abs(d) >= Float.MIN_NORMAL) {
+ // common situation
+ result = ((factor + FLOAT_EXPONENT_BIAS) << FLOAT_MANTISSA_BITS)
+ | (bits & FLOAT_MANTISSA_MASK);
+ } else {
+ // origin d is sub-normal, change mantissa to normal style
+ result = ((factor + FLOAT_EXPONENT_BIAS) << FLOAT_MANTISSA_BITS)
+ | ((bits << (subNormalFactor + 1)) & FLOAT_MANTISSA_MASK);
+ }
+ }
+ return Float.intBitsToFloat(result | sign);
+ }
+
+ // Shifts integer bits as float, if the digits is positive, left-shift; if
+ // not, shift to right and calculate its carry.
+ private static int shiftIntBits(int bits, int digits) {
+ if (digits > 0) {
+ return bits << digits;
+ }
+ // change it to positive
+ int absdigits = -digits;
+ if (!(Integer.numberOfLeadingZeros(bits & ~FLOAT_SIGN_MASK) <= (32 - absdigits))) {
+ return 0;
+ }
+ int ret = bits >> absdigits;
+ boolean halfbit = ((bits >> (absdigits - 1)) & 0x1) == 1;
+ if (halfbit) {
+ if (Integer.numberOfTrailingZeros(bits) < (absdigits - 1)) {
+ ret = ret + 1;
+ }
+ if (Integer.numberOfTrailingZeros(bits) == (absdigits - 1)) {
+ if ((ret & 0x1) == 1) {
+ ret = ret + 1;
+ }
+ }
+ }
+ return ret;
+ }
+
+ // Shifts long bits as double, if the digits is positive, left-shift; if
+ // not, shift to right and calculate its carry.
+ private static long shiftLongBits(long bits, long digits) {
+ if (digits > 0) {
+ return bits << digits;
+ }
+ // change it to positive
+ long absdigits = -digits;
+ if (!(Long.numberOfLeadingZeros(bits & ~DOUBLE_SIGN_MASK) <= (64 - absdigits))) {
+ return 0;
+ }
+ long ret = bits >> absdigits;
+ boolean halfbit = ((bits >> (absdigits - 1)) & 0x1) == 1;
+ if (halfbit) {
+ // some bits will remain after shifting, calculates its carry
+ // subnormal
+ if (Long.numberOfTrailingZeros(bits) < (absdigits - 1)) {
+ ret = ret + 1;
+ }
+ if (Long.numberOfTrailingZeros(bits) == (absdigits - 1)) {
+ if ((ret & 0x1) == 1) {
+ ret = ret + 1;
+ }
+ }
+ }
+ return ret;
}
}
Modified: harmony/enhanced/classlib/branches/java6/modules/luni/src/test/java/org/apache/harmony/luni/tests/java/lang/MathTest.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/branches/java6/modules/luni/src/test/java/org/apache/harmony/luni/tests/java/lang/MathTest.java?view=diff&rev=547215&r1=547214&r2=547215
==============================================================================
--- harmony/enhanced/classlib/branches/java6/modules/luni/src/test/java/org/apache/harmony/luni/tests/java/lang/MathTest.java (original)
+++ harmony/enhanced/classlib/branches/java6/modules/luni/src/test/java/org/apache/harmony/luni/tests/java/lang/MathTest.java Thu Jun 14 03:59:09 2007
@@ -1003,6 +1003,307 @@
// Test for method int java.lang.Math.round(float)
assertEquals("Incorrect rounding of a float", -91, Math.round(-90.89f));
}
+
+ /**
+ * @tests {@link java.lang.Math#scalb(double, int)}
+ * @since 1.6
+ */
+ @SuppressWarnings("boxing")
+ public void test_scalb_DI() {
+ // result is normal
+ assertEquals(4.1422946304E7, Math.scalb(1.2345, 25));
+ assertEquals(3.679096698760986E-8, Math.scalb(1.2345, -25));
+ assertEquals(1.2345, Math.scalb(1.2345, 0));
+ assertEquals(7868514.304, Math.scalb(0.2345, 25));
+
+ double normal = Math.scalb(0.2345, -25);
+ assertEquals(6.98864459991455E-9, normal);
+ // precision kept
+ assertEquals(0.2345, Math.scalb(normal, 25));
+
+ assertEquals(0.2345, Math.scalb(0.2345, 0));
+ assertEquals(-4.1422946304E7, Math.scalb(-1.2345, 25));
+ assertEquals(-6.98864459991455E-9, Math.scalb(-0.2345, -25));
+ assertEquals(2.0, Math.scalb(Double.MIN_NORMAL / 2, 1024));
+ assertEquals(64.0, Math.scalb(Double.MIN_VALUE, 1080));
+ assertEquals(234, Math.getExponent(Math.scalb(1.0, 234)));
+ assertEquals(3.9999999999999996, Math.scalb(Double.MAX_VALUE,
+ Double.MIN_EXPONENT));
+
+ // result is near infinity
+ double halfMax = Math.scalb(1.0, Double.MAX_EXPONENT);
+ assertEquals(8.98846567431158E307, halfMax);
+ assertEquals(Double.MAX_VALUE, halfMax - Math.ulp(halfMax) + halfMax);
+ assertEquals(Double.POSITIVE_INFINITY, halfMax + halfMax);
+ assertEquals(1.7976931348623155E308, Math.scalb(1.0 - Math.ulp(1.0),
+ Double.MAX_EXPONENT + 1));
+ assertEquals(Double.POSITIVE_INFINITY, Math.scalb(1.0 - Math.ulp(1.0),
+ Double.MAX_EXPONENT + 2));
+
+ halfMax = Math.scalb(-1.0, Double.MAX_EXPONENT);
+ assertEquals(-8.98846567431158E307, halfMax);
+ assertEquals(-Double.MAX_VALUE, halfMax + Math.ulp(halfMax) + halfMax);
+ assertEquals(Double.NEGATIVE_INFINITY, halfMax + halfMax);
+
+ assertEquals(Double.POSITIVE_INFINITY, Math.scalb(0.345, 1234));
+ assertEquals(Double.POSITIVE_INFINITY, Math.scalb(44.345E102, 934));
+ assertEquals(Double.NEGATIVE_INFINITY, Math.scalb(-44.345E102, 934));
+
+ assertEquals(Double.POSITIVE_INFINITY, Math.scalb(
+ Double.MIN_NORMAL / 2, 4000));
+ assertEquals(Double.POSITIVE_INFINITY, Math.scalb(Double.MIN_VALUE,
+ 8000));
+ assertEquals(Double.POSITIVE_INFINITY, Math.scalb(Double.MAX_VALUE, 1));
+ assertEquals(Double.POSITIVE_INFINITY, Math.scalb(
+ Double.POSITIVE_INFINITY, 0));
+ assertEquals(Double.POSITIVE_INFINITY, Math.scalb(
+ Double.POSITIVE_INFINITY, -1));
+ assertEquals(Double.NEGATIVE_INFINITY, Math.scalb(
+ Double.NEGATIVE_INFINITY, -1));
+ assertEquals(Double.NEGATIVE_INFINITY, Math.scalb(
+ Double.NEGATIVE_INFINITY, Double.MIN_EXPONENT));
+
+ // result is subnormal/zero
+ long posZeroBits = Double.doubleToLongBits(+0.0);
+ long negZeroBits = Double.doubleToLongBits(-0.0);
+ assertEquals(posZeroBits, Double.doubleToLongBits(Math.scalb(+0.0,
+ Integer.MAX_VALUE)));
+ assertEquals(posZeroBits, Double.doubleToLongBits(Math
+ .scalb(+0.0, -123)));
+ assertEquals(posZeroBits, Double.doubleToLongBits(Math.scalb(+0.0, 0)));
+ assertEquals(negZeroBits, Double
+ .doubleToLongBits(Math.scalb(-0.0, 123)));
+ assertEquals(negZeroBits, Double.doubleToLongBits(Math.scalb(-0.0,
+ Integer.MIN_VALUE)));
+
+ assertEquals(Double.MIN_VALUE, Math.scalb(1.0, -1074));
+ assertEquals(posZeroBits, Double.doubleToLongBits(Math
+ .scalb(1.0, -1075)));
+ assertEquals(negZeroBits, Double.doubleToLongBits(Math.scalb(-1.0,
+ -1075)));
+
+ // precision lost
+ assertEquals(Math.scalb(21.405, -1078), Math.scalb(21.405, -1079));
+ assertEquals(Double.MIN_VALUE, Math.scalb(21.405, -1079));
+ assertEquals(-Double.MIN_VALUE, Math.scalb(-21.405, -1079));
+ assertEquals(posZeroBits, Double.doubleToLongBits(Math.scalb(21.405,
+ -1080)));
+ assertEquals(negZeroBits, Double.doubleToLongBits(Math.scalb(-21.405,
+ -1080)));
+ assertEquals(posZeroBits, Double.doubleToLongBits(Math.scalb(
+ Double.MIN_VALUE, -1)));
+ assertEquals(negZeroBits, Double.doubleToLongBits(Math.scalb(
+ -Double.MIN_VALUE, -1)));
+ assertEquals(Double.MIN_VALUE, Math.scalb(Double.MIN_NORMAL, -52));
+ assertEquals(posZeroBits, Double.doubleToLongBits(Math.scalb(
+ Double.MIN_NORMAL, -53)));
+ assertEquals(negZeroBits, Double.doubleToLongBits(Math.scalb(
+ -Double.MIN_NORMAL, -53)));
+ assertEquals(Double.MIN_VALUE, Math.scalb(Double.MAX_VALUE, -2098));
+ assertEquals(posZeroBits, Double.doubleToLongBits(Math.scalb(
+ Double.MAX_VALUE, -2099)));
+ assertEquals(negZeroBits, Double.doubleToLongBits(Math.scalb(
+ -Double.MAX_VALUE, -2099)));
+ assertEquals(Double.MIN_VALUE, Math.scalb(Double.MIN_NORMAL / 3, -51));
+ assertEquals(posZeroBits, Double.doubleToLongBits(Math.scalb(
+ Double.MIN_NORMAL / 3, -52)));
+ assertEquals(negZeroBits, Double.doubleToLongBits(Math.scalb(
+ -Double.MIN_NORMAL / 3, -52)));
+ double subnormal = Math.scalb(Double.MIN_NORMAL / 3, -25);
+ assertEquals(2.2104123E-316, subnormal);
+ // precision lost
+ assertFalse(Double.MIN_NORMAL / 3 == Math.scalb(subnormal, 25));
+
+ // NaN
+ assertTrue(Double.isNaN(Math.scalb(Double.NaN, 1)));
+ assertTrue(Double.isNaN(Math.scalb(Double.NaN, 0)));
+ assertTrue(Double.isNaN(Math.scalb(Double.NaN, -120)));
+
+ assertEquals(1283457024, Double.doubleToLongBits(Math.scalb(
+ Double.MIN_VALUE * 153, 23)));
+ assertEquals(-9223372035571318784L, Double.doubleToLongBits(Math.scalb(
+ -Double.MIN_VALUE * 153, 23)));
+ assertEquals(36908406321184768L, Double.doubleToLongBits(Math.scalb(
+ Double.MIN_VALUE * 153, 52)));
+ assertEquals(-9186463630533591040L, Double.doubleToLongBits(Math.scalb(
+ -Double.MIN_VALUE * 153, 52)));
+
+ // test for exception
+ try {
+ Math.scalb((Double) null, (Integer) null);
+ fail("Should throw NullPointerException");
+ } catch (NullPointerException e) {
+ // Expected
+ }
+ try {
+ Math.scalb(1.0, (Integer) null);
+ fail("Should throw NullPointerException");
+ } catch (NullPointerException e) {
+ // Expected
+ }
+ try {
+ Math.scalb((Double) null, 1);
+ fail("Should throw NullPointerException");
+ } catch (NullPointerException e) {
+ // Expected
+ }
+
+ long b1em1022 = 0x0010000000000000L; // bit representation of
+ // Double.MIN_NORMAL
+ long b1em1023 = 0x0008000000000000L; // bit representation of half of
+ // Double.MIN_NORMAL
+ // assert exact identity
+ assertEquals(b1em1023, Double.doubleToLongBits(Math.scalb(Double
+ .longBitsToDouble(b1em1022), -1)));
+ }
+
+ /**
+ * @tests {@link java.lang.Math#scalb(float, int)}
+ * @since 1.6
+ */
+ @SuppressWarnings("boxing")
+ public void test_scalb_FI() {
+ // result is normal
+ assertEquals(4.1422946304E7f, Math.scalb(1.2345f, 25));
+ assertEquals(3.679096698760986E-8f, Math.scalb(1.2345f, -25));
+ assertEquals(1.2345f, Math.scalb(1.2345f, 0));
+ assertEquals(7868514.304f, Math.scalb(0.2345f, 25));
+
+ float normal = Math.scalb(0.2345f, -25);
+ assertEquals(6.98864459991455E-9f, normal);
+ // precision kept
+ assertEquals(0.2345f, Math.scalb(normal, 25));
+
+ assertEquals(0.2345f, Math.scalb(0.2345f, 0));
+ assertEquals(-4.1422946304E7f, Math.scalb(-1.2345f, 25));
+ assertEquals(-6.98864459991455E-9f, Math.scalb(-0.2345f, -25));
+ assertEquals(2.0f, Math.scalb(Float.MIN_NORMAL / 2, 128));
+ assertEquals(64.0f, Math.scalb(Float.MIN_VALUE, 155));
+ assertEquals(34, Math.getExponent(Math.scalb(1.0f, 34)));
+ assertEquals(3.9999998f, Math
+ .scalb(Float.MAX_VALUE, Float.MIN_EXPONENT));
+
+ // result is near infinity
+ float halfMax = Math.scalb(1.0f, Float.MAX_EXPONENT);
+ assertEquals(1.7014118E38f, halfMax);
+ assertEquals(Float.MAX_VALUE, halfMax - Math.ulp(halfMax) + halfMax);
+ assertEquals(Float.POSITIVE_INFINITY, halfMax + halfMax);
+ assertEquals(3.4028233E38f, Math.scalb(1.0f - Math.ulp(1.0f),
+ Float.MAX_EXPONENT + 1));
+ assertEquals(Float.POSITIVE_INFINITY, Math.scalb(1.0f - Math.ulp(1.0f),
+ Float.MAX_EXPONENT + 2));
+
+ halfMax = Math.scalb(-1.0f, Float.MAX_EXPONENT);
+ assertEquals(-1.7014118E38f, halfMax);
+ assertEquals(-Float.MAX_VALUE, halfMax + Math.ulp(halfMax) + halfMax);
+ assertEquals(Float.NEGATIVE_INFINITY, halfMax + halfMax);
+
+ assertEquals(Float.POSITIVE_INFINITY, Math.scalb(0.345f, 1234));
+ assertEquals(Float.POSITIVE_INFINITY, Math.scalb(44.345E10f, 934));
+ assertEquals(Float.NEGATIVE_INFINITY, Math.scalb(-44.345E10f, 934));
+
+ assertEquals(Float.POSITIVE_INFINITY, Math.scalb(Float.MIN_NORMAL / 2,
+ 400));
+ assertEquals(Float.POSITIVE_INFINITY, Math.scalb(Float.MIN_VALUE, 800));
+ assertEquals(Float.POSITIVE_INFINITY, Math.scalb(Float.MAX_VALUE, 1));
+ assertEquals(Float.POSITIVE_INFINITY, Math.scalb(
+ Float.POSITIVE_INFINITY, 0));
+ assertEquals(Float.POSITIVE_INFINITY, Math.scalb(
+ Float.POSITIVE_INFINITY, -1));
+ assertEquals(Float.NEGATIVE_INFINITY, Math.scalb(
+ Float.NEGATIVE_INFINITY, -1));
+ assertEquals(Float.NEGATIVE_INFINITY, Math.scalb(
+ Float.NEGATIVE_INFINITY, Float.MIN_EXPONENT));
+
+ // result is subnormal/zero
+ int posZeroBits = Float.floatToIntBits(+0.0f);
+ int negZeroBits = Float.floatToIntBits(-0.0f);
+ assertEquals(posZeroBits, Float.floatToIntBits(Math.scalb(+0.0f,
+ Integer.MAX_VALUE)));
+ assertEquals(posZeroBits, Float.floatToIntBits(Math.scalb(+0.0f, -123)));
+ assertEquals(posZeroBits, Float.floatToIntBits(Math.scalb(+0.0f, 0)));
+ assertEquals(negZeroBits, Float.floatToIntBits(Math.scalb(-0.0f, 123)));
+ assertEquals(negZeroBits, Float.floatToIntBits(Math.scalb(-0.0f,
+ Integer.MIN_VALUE)));
+
+ assertEquals(Float.MIN_VALUE, Math.scalb(1.0f, -149));
+ assertEquals(posZeroBits, Float.floatToIntBits(Math.scalb(1.0f, -150)));
+ assertEquals(negZeroBits, Float.floatToIntBits(Math.scalb(-1.0f, -150)));
+
+ // precision lost
+ assertEquals(Math.scalb(21.405f, -154), Math.scalb(21.405f, -153));
+ assertEquals(Float.MIN_VALUE, Math.scalb(21.405f, -154));
+ assertEquals(-Float.MIN_VALUE, Math.scalb(-21.405f, -154));
+ assertEquals(posZeroBits, Float.floatToIntBits(Math
+ .scalb(21.405f, -155)));
+ assertEquals(negZeroBits, Float.floatToIntBits(Math.scalb(-21.405f,
+ -155)));
+ assertEquals(posZeroBits, Float.floatToIntBits(Math.scalb(
+ Float.MIN_VALUE, -1)));
+ assertEquals(negZeroBits, Float.floatToIntBits(Math.scalb(
+ -Float.MIN_VALUE, -1)));
+ assertEquals(Float.MIN_VALUE, Math.scalb(Float.MIN_NORMAL, -23));
+ assertEquals(posZeroBits, Float.floatToIntBits(Math.scalb(
+ Float.MIN_NORMAL, -24)));
+ assertEquals(negZeroBits, Float.floatToIntBits(Math.scalb(
+ -Float.MIN_NORMAL, -24)));
+ assertEquals(Float.MIN_VALUE, Math.scalb(Float.MAX_VALUE, -277));
+ assertEquals(posZeroBits, Float.floatToIntBits(Math.scalb(
+ Float.MAX_VALUE, -278)));
+ assertEquals(negZeroBits, Float.floatToIntBits(Math.scalb(
+ -Float.MAX_VALUE, -278)));
+ assertEquals(Float.MIN_VALUE, Math.scalb(Float.MIN_NORMAL / 3, -22));
+ assertEquals(posZeroBits, Float.floatToIntBits(Math.scalb(
+ Float.MIN_NORMAL / 3, -23)));
+ assertEquals(negZeroBits, Float.floatToIntBits(Math.scalb(
+ -Float.MIN_NORMAL / 3, -23)));
+ float subnormal = Math.scalb(Float.MIN_NORMAL / 3, -11);
+ assertEquals(1.913E-42f, subnormal);
+ // precision lost
+ assertFalse(Float.MIN_NORMAL / 3 == Math.scalb(subnormal, 11));
+
+ assertEquals(68747264, Float.floatToIntBits(Math.scalb(
+ Float.MIN_VALUE * 153, 23)));
+ assertEquals(-2078736384, Float.floatToIntBits(Math.scalb(
+ -Float.MIN_VALUE * 153, 23)));
+
+ assertEquals(4896, Float.floatToIntBits(Math.scalb(
+ Float.MIN_VALUE * 153, 5)));
+ assertEquals(-2147478752, Float.floatToIntBits(Math.scalb(
+ -Float.MIN_VALUE * 153, 5)));
+
+ // NaN
+ assertTrue(Float.isNaN(Math.scalb(Float.NaN, 1)));
+ assertTrue(Float.isNaN(Math.scalb(Float.NaN, 0)));
+ assertTrue(Float.isNaN(Math.scalb(Float.NaN, -120)));
+
+ // test for exception
+ try {
+ Math.scalb((Float) null, (Integer) null);
+ fail("Should throw NullPointerException");
+ } catch (NullPointerException e) {
+ // Expected
+ }
+ try {
+ Math.scalb(1.0f, (Integer) null);
+ fail("Should throw NullPointerException");
+ } catch (NullPointerException e) {
+ // Expected
+ }
+ try {
+ Math.scalb((Float) null, 1);
+ fail("Should throw NullPointerException");
+ } catch (NullPointerException e) {
+ // Expected
+ }
+
+ int b1em126 = 0x00800000; // bit representation of Float.MIN_NORMAL
+ int b1em127 = 0x00400000; // bit representation of half
+ // Float.MIN_NORMAL
+ // assert exact identity
+ assertEquals(b1em127, Float.floatToIntBits(Math.scalb(Float
+ .intBitsToFloat(b1em126), -1)));
+ }
/**
* @tests java.lang.Math#signum(double)
@@ -1252,5 +1553,101 @@
.ulp(1153.0f), 0f);
assertEquals("Returned incorrect value", 5.6E-45f, Math
.ulp(9.403954E-38f), 0f);
+ }
+
+ /**
+ * @tests {@link java.lang.Math#shiftIntBits(int, int)}
+ *
+ * @since 1.6
+ */
+ public void test_shiftIntBits_II() {
+ class Tuple {
+ public int result;
+
+ public int value;
+
+ public int factor;
+
+ public Tuple(int result, int value, int factor) {
+ this.result = result;
+ this.value = value;
+ this.factor = factor;
+ }
+ }
+ final Tuple[] TUPLES = new Tuple[] {
+ // sub-normal to sub-normal
+ new Tuple(0x00000000, 0x00000001, -1),
+ // round to even
+ new Tuple(0x00000002, 0x00000003, -1),
+ // round to even
+ new Tuple(0x00000001, 0x00000005, -3),
+ // round to infinity
+ new Tuple(0x00000002, 0x0000000d, -3),
+ // round to infinity
+
+ // normal to sub-normal
+ new Tuple(0x00000002, 0x01a00000, -24),
+ // round to even
+ new Tuple(0x00000004, 0x01e00000, -24),
+ // round to even
+ new Tuple(0x00000003, 0x01c80000, -24),
+ // round to infinity
+ new Tuple(0x00000004, 0x01e80000, -24),
+ // round to infinity
+ };
+ for (int i = 0; i < TUPLES.length; ++i) {
+ Tuple tuple = TUPLES[i];
+ assertEquals(tuple.result, Float.floatToIntBits(Math.scalb(Float
+ .intBitsToFloat(tuple.value), tuple.factor)));
+ assertEquals(tuple.result, Float.floatToIntBits(-Math.scalb(-Float
+ .intBitsToFloat(tuple.value), tuple.factor)));
+ }
+ }
+
+ /**
+ * @tests {@link java.lang.Math#shiftLongBits(long, long)}
+ *
+ * Round result to nearest value on precision lost.
+ *
+ * @since 1.6
+ */
+ public void test_shiftLongBits_LL() {
+ class Tuple {
+ public long result;
+
+ public long value;
+
+ public int factor;
+
+ public Tuple(long result, long value, int factor) {
+ this.result = result;
+ this.value = value;
+ this.factor = factor;
+ }
+ }
+ final Tuple[] TUPLES = new Tuple[] {
+ // sub-normal to sub-normal
+ new Tuple(0x00000000L, 0x00000001L, -1),
+ //round to even
+ new Tuple(0x00000002L, 0x00000003L, -1),
+ //round to even
+ new Tuple(0x00000001L, 0x00000005L, -3),
+ //round to infinity
+ new Tuple(0x00000002L, 0x0000000dL, -3),
+ //round to infinity
+
+ // normal to sub-normal
+ new Tuple(0x0000000000000002L, 0x0034000000000000L, -53), // round to even
+ new Tuple(0x0000000000000004L, 0x003c000000000000L, -53), // round to even
+ new Tuple(0x0000000000000003L, 0x0035000000000000L, -53), // round to infinity
+ new Tuple(0x0000000000000004L, 0x003d000000000000L, -53), // round to infinity
+ };
+ for (int i = 0; i < TUPLES.length; ++i) {
+ Tuple tuple = TUPLES[i];
+ assertEquals(tuple.result, Double.doubleToLongBits(Math.scalb(
+ Double.longBitsToDouble(tuple.value), tuple.factor)));
+ assertEquals(tuple.result, Double.doubleToLongBits(-Math.scalb(
+ -Double.longBitsToDouble(tuple.value), tuple.factor)));
+ }
}
}