Author: luc
Date: Sun Jan 23 22:19:37 2011
New Revision: 1062549
URL: http://svn.apache.org/viewvc?rev=1062549&view=rev
Log:
added FastMath.scalb(double, int) and FastMath.scalb(float, int)
deprecated MathUtils.scalb(double, int)
JIRA: MATH-498
Modified:
commons/proper/math/branches/MATH_2_X/src/main/java/org/apache/commons/math/util/FastMath.java
commons/proper/math/branches/MATH_2_X/src/main/java/org/apache/commons/math/util/MathUtils.java
commons/proper/math/branches/MATH_2_X/src/site/xdoc/changes.xml
commons/proper/math/branches/MATH_2_X/src/test/java/org/apache/commons/math/util/FastMathTest.java
commons/proper/math/branches/MATH_2_X/src/test/java/org/apache/commons/math/util/MathUtilsTest.java
Modified:
commons/proper/math/branches/MATH_2_X/src/main/java/org/apache/commons/math/util/FastMath.java
URL:
http://svn.apache.org/viewvc/commons/proper/math/branches/MATH_2_X/src/main/java/org/apache/commons/math/util/FastMath.java?rev=1062549&r1=1062548&r2=1062549&view=diff
==============================================================================
---
commons/proper/math/branches/MATH_2_X/src/main/java/org/apache/commons/math/util/FastMath.java
(original)
+++
commons/proper/math/branches/MATH_2_X/src/main/java/org/apache/commons/math/util/FastMath.java
Sun Jan 23 22:19:37 2011
@@ -3401,6 +3401,162 @@ public class FastMath {
}
/**
+ * Multiply a double number by a power of 2.
+ * @param d number to multiply
+ * @param n power of 2
+ * @return d × 2<sup>n</sup>
+ */
+ public static double scalb(final double d, final int n) {
+
+ // first simple and fast handling when 2^n can be represented using
normal numbers
+ if ((n > -1023) && (n < 1024)) {
+ return d * Double.longBitsToDouble(((long) (n + 1023)) << 52);
+ }
+
+ // handle special cases
+ if (Double.isNaN(d) || Double.isInfinite(d) || (d == 0)) {
+ return d;
+ }
+
+ // decompose d
+ final long bits = Double.doubleToLongBits(d);
+ final long sign = bits & 0x8000000000000000L;
+ int exponent = ((int) (bits >>> 52)) & 0x7ff;
+ long mantissa = bits & 0x000fffffffffffffL;
+
+ // compute scaled exponent
+ int scaledExponent = exponent + n;
+
+ if (n < 0) {
+ // we are really in the case n <= -1023
+ if (scaledExponent > 0) {
+ // both the input and the result are normal numbers, we only
adjust the exponent
+ return Double.longBitsToDouble(sign | (((long) scaledExponent)
<< 52) | mantissa);
+ } else if (scaledExponent > -53) {
+ // the input is a normal number and the result is a subnormal
number
+
+ // recover the hidden mantissa bit
+ mantissa = mantissa | (1L << 52);
+
+ // scales down complete mantissa, hence losing least
significant bits
+ final long mostSignificantLostBit = mantissa & (1L <<
(-scaledExponent));
+ mantissa = mantissa >>> (1 - scaledExponent);
+ if (mostSignificantLostBit != 0) {
+ // we need to add 1 bit to round up the result
+ mantissa++;
+ }
+ return Double.longBitsToDouble(sign | mantissa);
+
+ } else {
+ // no need to compute the mantissa, the number scales down to 0
+ return (sign == 0L) ? 0.0 : -0.0;
+ }
+ } else {
+ // we are really in the case n >= 1024
+ if (exponent == 0) {
+
+ // the input number is subnormal, normalize it
+ while ((mantissa >>> 52) != 1) {
+ mantissa = mantissa << 1;
+ --scaledExponent;
+ }
+ ++scaledExponent;
+ mantissa = mantissa & 0x000fffffffffffffL;
+
+ if (scaledExponent < 2047) {
+ return Double.longBitsToDouble(sign | (((long)
scaledExponent) << 52) | mantissa);
+ } else {
+ return (sign == 0L) ? Double.POSITIVE_INFINITY :
Double.NEGATIVE_INFINITY;
+ }
+
+ } else if (scaledExponent < 2047) {
+ return Double.longBitsToDouble(sign | (((long) scaledExponent)
<< 52) | mantissa);
+ } else {
+ return (sign == 0L) ? Double.POSITIVE_INFINITY :
Double.NEGATIVE_INFINITY;
+ }
+ }
+
+ }
+
+ /**
+ * Multiply a float number by a power of 2.
+ * @param f number to multiply
+ * @param n power of 2
+ * @return f × 2<sup>n</sup>
+ */
+ public static float scalb(final float f, final int n) {
+
+ // first simple and fast handling when 2^n can be represented using
normal numbers
+ if ((n > -127) && (n < 128)) {
+ return f * Float.intBitsToFloat((n + 127) << 23);
+ }
+
+ // handle special cases
+ if (Float.isNaN(f) || Float.isInfinite(f) || (f == 0f)) {
+ return f;
+ }
+
+ // decompose f
+ final int bits = Float.floatToIntBits(f);
+ final int sign = bits & 0x80000000;
+ int exponent = (bits >>> 23) & 0xff;
+ int mantissa = bits & 0x007fffff;
+
+ // compute scaled exponent
+ int scaledExponent = exponent + n;
+
+ if (n < 0) {
+ // we are really in the case n <= -127
+ if (scaledExponent > 0) {
+ // both the input and the result are normal numbers, we only
adjust the exponent
+ return Float.intBitsToFloat(sign | (scaledExponent << 23) |
mantissa);
+ } else if (scaledExponent > -24) {
+ // the input is a normal number and the result is a subnormal
number
+
+ // recover the hidden mantissa bit
+ mantissa = mantissa | (1 << 23);
+
+ // scales down complete mantissa, hence losing least
significant bits
+ final int mostSignificantLostBit = mantissa & (1 <<
(-scaledExponent));
+ mantissa = mantissa >>> (1 - scaledExponent);
+ if (mostSignificantLostBit != 0) {
+ // we need to add 1 bit to round up the result
+ mantissa++;
+ }
+ return Float.intBitsToFloat(sign | mantissa);
+
+ } else {
+ // no need to compute the mantissa, the number scales down to 0
+ return (sign == 0) ? 0.0f : -0.0f;
+ }
+ } else {
+ // we are really in the case n >= 128
+ if (exponent == 0) {
+
+ // the input number is subnormal, normalize it
+ while ((mantissa >>> 23) != 1) {
+ mantissa = mantissa << 1;
+ --scaledExponent;
+ }
+ ++scaledExponent;
+ mantissa = mantissa & 0x007fffff;
+
+ if (scaledExponent < 255) {
+ return Float.intBitsToFloat(sign | (scaledExponent << 23)
| mantissa);
+ } else {
+ return (sign == 0) ? Float.POSITIVE_INFINITY :
Float.NEGATIVE_INFINITY;
+ }
+
+ } else if (scaledExponent < 255) {
+ return Float.intBitsToFloat(sign | (scaledExponent << 23) |
mantissa);
+ } else {
+ return (sign == 0) ? Float.POSITIVE_INFINITY :
Float.NEGATIVE_INFINITY;
+ }
+ }
+
+ }
+
+ /**
* Get the next machine representable number after a number, moving
* in the direction of another number.
* <p>
Modified:
commons/proper/math/branches/MATH_2_X/src/main/java/org/apache/commons/math/util/MathUtils.java
URL:
http://svn.apache.org/viewvc/commons/proper/math/branches/MATH_2_X/src/main/java/org/apache/commons/math/util/MathUtils.java?rev=1062549&r1=1062548&r2=1062549&view=diff
==============================================================================
---
commons/proper/math/branches/MATH_2_X/src/main/java/org/apache/commons/math/util/MathUtils.java
(original)
+++
commons/proper/math/branches/MATH_2_X/src/main/java/org/apache/commons/math/util/MathUtils.java
Sun Jan 23 22:19:37 2011
@@ -1301,26 +1301,14 @@ public final class MathUtils {
* <p>If <code>d</code> is 0 or NaN or Infinite, it is returned
unchanged.</p>
*
* @param d base number
- * @param scaleFactor power of two by which d sould be multiplied
+ * @param scaleFactor power of two by which d should be multiplied
* @return d × 2<sup>scaleFactor</sup>
* @since 2.0
+ * @deprecated as of 2.2, replaced by {@link FastMath#scalb(double, int)}
*/
+ @Deprecated
public static double scalb(final double d, final int scaleFactor) {
-
- // handling of some important special cases
- if ((d == 0) || Double.isNaN(d) || Double.isInfinite(d)) {
- return d;
- }
-
- // split the double in raw components
- final long bits = Double.doubleToLongBits(d);
- final long exponent = bits & 0x7ff0000000000000L;
- final long rest = bits & 0x800fffffffffffffL;
-
- // shift the exponent
- final long newBits = rest | (exponent + (((long) scaleFactor) << 52));
- return Double.longBitsToDouble(newBits);
-
+ return FastMath.scalb(d, scaleFactor);
}
/**
Modified: commons/proper/math/branches/MATH_2_X/src/site/xdoc/changes.xml
URL:
http://svn.apache.org/viewvc/commons/proper/math/branches/MATH_2_X/src/site/xdoc/changes.xml?rev=1062549&r1=1062548&r2=1062549&view=diff
==============================================================================
--- commons/proper/math/branches/MATH_2_X/src/site/xdoc/changes.xml (original)
+++ commons/proper/math/branches/MATH_2_X/src/site/xdoc/changes.xml Sun Jan 23
22:19:37 2011
@@ -52,15 +52,19 @@ The <action> type attribute can be add,u
If the output is not quite correct, check for invisible trailing spaces!
-->
<release version="2.2" date="TBD" description="TBD">
+ <action dev="luc" type="fix" issue="MATH-498">
+ FastMath is not an exact replacement for StrictMath
+ (partially fixed) added scalb(double, int), scalb(float, int)
+ </action>
<action dev="luc" type="fix" issue="MATH-478">
FastMath is not an exact replacement for StrictMath
- (partially fixed) fixed nextAfter(double, double) and
nextAfter(float,double)
+ (partially fixed) added nextAfter(double, double) and
nextAfter(float,double)
(beware of the strange double second argument) so that they handle
special values in the way as StrictMath
</action>
<action dev="luc" type="fix" issue="MATH-497">
FastMath is not an exact replacement for StrictMath
- (partially fixed) Add getExponent(double), getExponent(float)
+ (partially fixed) added getExponent(double) and getExponent(float)
</action>
<action dev="sebb" type="fix" issue="MATH-496">
FastMath is not an exact replacement for StrictMath
Modified:
commons/proper/math/branches/MATH_2_X/src/test/java/org/apache/commons/math/util/FastMathTest.java
URL:
http://svn.apache.org/viewvc/commons/proper/math/branches/MATH_2_X/src/test/java/org/apache/commons/math/util/FastMathTest.java?rev=1062549&r1=1062548&r2=1062549&view=diff
==============================================================================
---
commons/proper/math/branches/MATH_2_X/src/test/java/org/apache/commons/math/util/FastMathTest.java
(original)
+++
commons/proper/math/branches/MATH_2_X/src/test/java/org/apache/commons/math/util/FastMathTest.java
Sun Jan 23 22:19:37 2011
@@ -1066,6 +1066,40 @@ public class FastMathTest {
Assert.assertEquals(0F, FastMath.nextAfter(-Float.MIN_VALUE, 1F), 0F);
}
+ @Test
+ public void testDoubleScalbSpecialCases() {
+ Assert.assertEquals(2.5269841324701218E-175,
FastMath.scalb(2.2250738585072014E-308, 442), 0D);
+ Assert.assertEquals(1.307993905256674E297,
FastMath.scalb(1.1102230246251565E-16, 1040), 0D);
+ Assert.assertEquals(7.2520887996488946E-217,
FastMath.scalb(Double.MIN_VALUE, 356), 0D);
+ Assert.assertEquals(8.98846567431158E307,
FastMath.scalb(Double.MIN_VALUE, 2097), 0D);
+ Assert.assertEquals(Double.POSITIVE_INFINITY,
FastMath.scalb(Double.MIN_VALUE, 2098), 0D);
+ Assert.assertEquals(1.1125369292536007E-308,
FastMath.scalb(2.225073858507201E-308, -1), 0D);
+ Assert.assertEquals(1.0E-323,
FastMath.scalb(Double.MAX_VALUE, -2097), 0D);
+ Assert.assertEquals(Double.MIN_VALUE,
FastMath.scalb(Double.MAX_VALUE, -2098), 0D);
+ Assert.assertEquals(0,
FastMath.scalb(Double.MAX_VALUE, -2099), 0D);
+ Assert.assertEquals(Double.POSITIVE_INFINITY,
FastMath.scalb(Double.POSITIVE_INFINITY, -1000000), 0D);
+ Assert.assertEquals(Double.NEGATIVE_INFINITY,
FastMath.scalb(-1.1102230246251565E-16, 1078), 0D);
+ Assert.assertEquals(Double.NEGATIVE_INFINITY,
FastMath.scalb(-1.1102230246251565E-16, 1079), 0D);
+ Assert.assertEquals(Double.NEGATIVE_INFINITY,
FastMath.scalb(-2.2250738585072014E-308, 2047), 0D);
+ Assert.assertEquals(Double.NEGATIVE_INFINITY,
FastMath.scalb(-2.2250738585072014E-308, 2048), 0D);
+ }
+
+ @Test
+ public void testFloatScalbSpecialCases() {
+ Assert.assertEquals(0f,
FastMath.scalb(Float.MIN_VALUE, -30), 0F);
+ Assert.assertEquals(2 * Float.MIN_VALUE,
FastMath.scalb(Float.MIN_VALUE, 1), 0F);
+ Assert.assertEquals(7.555786e22f,
FastMath.scalb(Float.MAX_VALUE, -52), 0F);
+ Assert.assertEquals(1.7014118e38f,
FastMath.scalb(Float.MIN_VALUE, 276), 0F);
+ Assert.assertEquals(Float.POSITIVE_INFINITY,
FastMath.scalb(Float.MIN_VALUE, 277), 0F);
+ Assert.assertEquals(5.8774718e-39f,
FastMath.scalb(1.1754944e-38f, -1), 0F);
+ Assert.assertEquals(2 * Float.MIN_VALUE,
FastMath.scalb(Float.MAX_VALUE, -276), 0F);
+ Assert.assertEquals(Float.MIN_VALUE,
FastMath.scalb(Float.MAX_VALUE, -277), 0F);
+ Assert.assertEquals(0,
FastMath.scalb(Float.MAX_VALUE, -278), 0F);
+ Assert.assertEquals(Float.POSITIVE_INFINITY,
FastMath.scalb(Float.POSITIVE_INFINITY, -1000000), 0F);
+ Assert.assertEquals(-3.13994498e38f, FastMath.scalb(-1.1e-7f,
151), 0F);
+ Assert.assertEquals(Float.NEGATIVE_INFINITY, FastMath.scalb(-1.1e-7f,
152), 0F);
+ }
+
private static void reportError(String message) {
final boolean fatal = false;
if (fatal) {
Modified:
commons/proper/math/branches/MATH_2_X/src/test/java/org/apache/commons/math/util/MathUtilsTest.java
URL:
http://svn.apache.org/viewvc/commons/proper/math/branches/MATH_2_X/src/test/java/org/apache/commons/math/util/MathUtilsTest.java?rev=1062549&r1=1062548&r2=1062549&view=diff
==============================================================================
---
commons/proper/math/branches/MATH_2_X/src/test/java/org/apache/commons/math/util/MathUtilsTest.java
(original)
+++
commons/proper/math/branches/MATH_2_X/src/test/java/org/apache/commons/math/util/MathUtilsTest.java
Sun Jan 23 22:19:37 2011
@@ -957,16 +957,6 @@ public final class MathUtilsTest extends
}
}
- public void testScalb() {
- assertEquals( 0.0, MathUtils.scalb(0.0, 5), 1.0e-15);
- assertEquals(32.0, MathUtils.scalb(1.0, 5), 1.0e-15);
- assertEquals(1.0 / 32.0, MathUtils.scalb(1.0, -5), 1.0e-15);
- assertEquals(FastMath.PI, MathUtils.scalb(FastMath.PI, 0), 1.0e-15);
- assertTrue(Double.isInfinite(MathUtils.scalb(Double.POSITIVE_INFINITY,
1)));
- assertTrue(Double.isInfinite(MathUtils.scalb(Double.NEGATIVE_INFINITY,
1)));
- assertTrue(Double.isNaN(MathUtils.scalb(Double.NaN, 1)));
- }
-
public void testNormalizeAngle() {
for (double a = -15.0; a <= 15.0; a += 0.1) {
for (double b = -15.0; b <= 15.0; b += 0.2) {