Add tests for java.lang.Math and fix incompatibilities

Change-Id: Id1e5972a24ccae486d73e69f785e093615d8b8e8
diff --git a/user/super/com/google/gwt/emul/java/lang/Math.java b/user/super/com/google/gwt/emul/java/lang/Math.java
index 2f01351..922ef5d 100644
--- a/user/super/com/google/gwt/emul/java/lang/Math.java
+++ b/user/super/com/google/gwt/emul/java/lang/Math.java
@@ -90,7 +90,7 @@
   }
 
   public static double cbrt(double x) {
-    return Math.pow(x, 1.0 / 3.0);
+    return x == 0 || !Double.isFinite(x) ? x : NativeMath.pow(x, 1.0 / 3.0);
   }
 
   public static double ceil(double x) {
@@ -98,7 +98,7 @@
   }
 
   public static double copySign(double magnitude, double sign) {
-    return isNegative(sign) ? -Math.abs(magnitude) : Math.abs(magnitude);
+    return isNegative(sign) ? -NativeMath.abs(magnitude) : NativeMath.abs(magnitude);
   }
 
   private static boolean isNegative(double d) {
@@ -106,7 +106,7 @@
   }
 
   public static float copySign(float magnitude, float sign) {
-    return (float) (copySign((double) magnitude, (double) sign));
+    return (float) copySign((double) magnitude, (double) sign);
   }
 
   public static double cos(double x) {
@@ -114,7 +114,7 @@
   }
 
   public static double cosh(double x) {
-    return (Math.exp(x) + Math.exp(-x)) / 2.0;
+    return (NativeMath.exp(x) + NativeMath.exp(-x)) / 2;
   }
 
   public static int decrementExact(int x) {
@@ -132,7 +132,7 @@
   }
 
   public static double expm1(double d) {
-    return d == 0 ? d : exp(d) - 1;
+    return d == 0 ? d : NativeMath.exp(d) - 1;
   }
 
   public static double floor(double x) {
@@ -162,7 +162,8 @@
   }
 
   public static double hypot(double x, double y) {
-    return sqrt(x * x + y * y);
+    return Double.isInfinite(x) || Double.isInfinite(y) ?
+        Double.POSITIVE_INFINITY : NativeMath.sqrt(x * x + y * y);
   }
 
   public static int incrementExact(int x) {
@@ -184,7 +185,7 @@
   }
 
   public static double log1p(double x) {
-    return Math.log(x + 1.0d);
+    return x == 0 ? x : NativeMath.log(x + 1);
   }
 
   public static double max(double x, double y) {
@@ -275,14 +276,9 @@
   }
 
   public static int round(float x) {
-    double roundedValue = NativeMath.round(x);
-    return unsafeCastToInt(roundedValue);
+    return (int) NativeMath.round(x);
   }
 
-  private static native int unsafeCastToInt(double d) /*-{
-    return d;
-  }-*/;
-
   public static int subtractExact(int x, int y) {
     double r = (double) x - (double) y;
     throwOverflowIf(!isSafeIntegerRange(r));
@@ -299,13 +295,13 @@
 
   public static double scalb(double d, int scaleFactor) {
     if (scaleFactor >= 31 || scaleFactor <= -31) {
-      return d * Math.pow(2, scaleFactor);
+      return d * NativeMath.pow(2, scaleFactor);
     } else if (scaleFactor > 0) {
       return d * (1 << scaleFactor);
     } else if (scaleFactor == 0) {
       return d;
     } else {
-      return d * 1.0d / (1 << -scaleFactor);
+      return d / (1 << -scaleFactor);
     }
   }
 
@@ -314,7 +310,7 @@
   }
 
   public static double signum(double d) {
-    if (d == 0. || Double.isNaN(d)) {
+    if (d == 0 || Double.isNaN(d)) {
       return d;
     } else {
       return d < 0 ? -1 : 1;
@@ -330,7 +326,7 @@
   }
 
   public static double sinh(double x) {
-    return (Math.exp(x) - Math.exp(-x)) / 2.0d;
+    return x == 0 ? x : (NativeMath.exp(x) - NativeMath.exp(-x)) / 2;
   }
 
   public static double sqrt(double x) {
@@ -342,12 +338,14 @@
   }
 
   public static double tanh(double x) {
-    if (Double.isInfinite(x)) {
+    if (x == 0.0) {
+      return x;
+    } else if (Double.isInfinite(x)) {
       return signum(x);
+    } else {
+      double e2x = NativeMath.exp(2 * x);
+      return (e2x - 1) / (e2x + 1);
     }
-
-    double e2x = Math.exp(2.0 * x);
-    return (e2x - 1) / (e2x + 1);
   }
 
   public static double toDegrees(double x) {
diff --git a/user/test/com/google/gwt/emultest/java/lang/MathTest.java b/user/test/com/google/gwt/emultest/java/lang/MathTest.java
index 3128b81..7557108 100644
--- a/user/test/com/google/gwt/emultest/java/lang/MathTest.java
+++ b/user/test/com/google/gwt/emultest/java/lang/MathTest.java
@@ -21,7 +21,6 @@
 /**
  * Tests for JRE emulation of java.lang.Math.
  *
- * TODO: more tests
  */
 public class MathTest extends GWTTestCase {
 
@@ -39,30 +38,32 @@
   }
 
   private static void assertEquals(double expected, double actual) {
-    assertEquals(expected, actual, 0.);
+    assertEquals(expected, actual, 0.0);
   }
 
   private static boolean isNegativeZero(double x) {
     return Double.doubleToLongBits(-0.0) == Double.doubleToLongBits(x);
   }
 
-  private static double makeNegativeZero() {
-    return -0.0;
-  }
-
   @Override
   public String getModuleName() {
     return "com.google.gwt.emultest.EmulSuite";
   }
 
+  @Override
+  protected void gwtSetUp() throws Exception {
+    // Ensure -0.0 vs 0.0 behavior
+    assertPositiveZero(0.0);
+    assertNegativeZero(-0.0);
+    assertFalse(isNegativeZero(0.0));
+  }
+
   public void testAbs() {
     double v = Math.abs(-1.0);
-    double negativeZero = makeNegativeZero();
-    assertTrue(isNegativeZero(negativeZero));
     assertEquals(1.0, v);
     v = Math.abs(1.0);
     assertEquals(1.0, v);
-    v = Math.abs(negativeZero);
+    v = Math.abs(-0.0);
     assertPositiveZero(v);
     v = Math.abs(0.0);
     assertPositiveZero(v);
@@ -74,14 +75,89 @@
     assertNaN(v);
   }
 
+  public void testAsin() {
+    assertNaN(Math.asin(Double.NaN));
+    assertNaN(Math.asin(1.1));
+    assertNaN(Math.asin(Double.NEGATIVE_INFINITY));
+    assertNaN(Math.asin(Double.POSITIVE_INFINITY));
+    assertPositiveZero(Math.asin(0.0));
+    assertNegativeZero(Math.asin(-0.0));
+
+    assertEquals(0.0, Math.asin(0));
+    assertEquals(1.570796326, Math.asin(1), 1e-7);
+  }
+
+  public void testAcos() {
+    assertNaN(Math.acos(Double.NaN));
+    assertNaN(Math.acos(1.1));
+    assertNaN(Math.acos(Double.NEGATIVE_INFINITY));
+    assertNaN(Math.acos(Double.POSITIVE_INFINITY));
+
+    assertEquals(0.0, Math.acos(1));
+    assertEquals(1.570796326, Math.acos(0), 1e-7);
+  }
+
+  public void testAtan() {
+    assertNaN(Math.atan(Double.NaN));
+    assertPositiveZero(Math.atan(0.0));
+    assertNegativeZero(Math.atan(-0.0));
+    assertEquals(-1.570796326, Math.atan(Double.NEGATIVE_INFINITY), 1e-7);
+    assertEquals(1.570796326, Math.atan(Double.POSITIVE_INFINITY), 1e-7);
+    assertEquals(0.785398163, Math.atan(1), 1e-7);
+  }
+
+  public void testAtan2() {
+    assertNaN(Math.atan2(Double.NaN, 1));
+    assertNaN(Math.atan2(1, Double.NaN));
+    assertNaN(Math.atan2(Double.NaN, Double.NaN));
+    assertPositiveZero(Math.atan2(0.0, 1.0));
+    assertPositiveZero(Math.atan2(1.0, Double.POSITIVE_INFINITY));
+    assertNegativeZero(Math.atan2(-0.0, 1.0));
+    assertNegativeZero(Math.atan2(-1.0, Double.POSITIVE_INFINITY));
+    assertEquals(Math.PI, Math.atan2(0.0, -1.0), 1e-7);
+    assertEquals(Math.PI, Math.atan2(1.0, Double.NEGATIVE_INFINITY), 1e-7);
+    assertEquals(-Math.PI, Math.atan2(-0.0, -1.0), 1e-7);
+    assertEquals(-Math.PI, Math.atan2(-1.0, Double.NEGATIVE_INFINITY), 1e-7);
+    assertEquals(Math.PI / 2, Math.atan2(1.0, 0.0), 1e-7);
+    assertEquals(Math.PI / 2, Math.atan2(1.0, -0.0), 1e-7);
+    assertEquals(Math.PI / 2, Math.atan2(Double.POSITIVE_INFINITY, 1.0), 1e-7);
+    assertEquals(-Math.PI / 2, Math.atan2(-1.0, 0.0), 1e-7);
+    assertEquals(-Math.PI / 2, Math.atan2(-1.0, -0.0), 1e-7);
+    assertEquals(-Math.PI / 2, Math.atan2(Double.NEGATIVE_INFINITY, 1.0), 1e-7);
+    assertEquals(Math.PI / 4, Math.atan2(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY), 1e-7);
+    assertEquals(Math.PI * 3 / 4,
+        Math.atan2(Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY), 1e-7);
+    assertEquals(-Math.PI / 4,
+        Math.atan2(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY), 1e-7);
+    assertEquals(-3 * Math.PI / 4,
+        Math.atan2(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY), 1e-7);
+
+    assertEquals(0.463647609, Math.atan2(1, 2), 1e-7);
+  }
+
   public void testCbrt() {
+    assertNaN(Math.cbrt(Double.NaN));
+    assertEquals(Double.POSITIVE_INFINITY, Math.cbrt(Double.POSITIVE_INFINITY));
+    assertEquals(Double.NEGATIVE_INFINITY, Math.cbrt(Double.NEGATIVE_INFINITY));
+    assertPositiveZero(Math.cbrt(0.0));
+    assertNegativeZero(Math.cbrt(-0.0));
+
     double v = Math.cbrt(1000.0);
     assertEquals(10.0, v, 1e-7);
   }
 
-  public void testCopySign() {
-    double negativeZero = makeNegativeZero();
+  public void testCeil() {
+    assertNaN(Math.ceil(Double.NaN));
+    assertEquals(Double.POSITIVE_INFINITY, Math.ceil(Double.POSITIVE_INFINITY));
+    assertEquals(Double.NEGATIVE_INFINITY, Math.ceil(Double.NEGATIVE_INFINITY));
+    assertPositiveZero(Math.ceil(0.0));
+    assertNegativeZero(Math.ceil(-0.0));
 
+    assertEquals(1.0, Math.ceil(0.5));
+    assertNegativeZero(Math.ceil(-0.5));
+  }
+
+  public void testCopySign() {
     assertEquals(3.0, Math.copySign(3.0, 2.0));
     assertEquals(3.0, Math.copySign(-3.0, 2.0));
     assertEquals(-3.0, Math.copySign(3.0, -2.0));
@@ -89,29 +165,29 @@
 
     assertEquals(2.0, Math.copySign(2.0, 0.0));
     assertEquals(2.0, Math.copySign(-2.0, 0.0));
-    assertEquals(-2.0, Math.copySign(2.0, negativeZero));
-    assertEquals(-2.0, Math.copySign(-2.0, negativeZero));
+    assertEquals(-2.0, Math.copySign(2.0, -0.0));
+    assertEquals(-2.0, Math.copySign(-2.0, -0.0));
     assertEquals(-2.0, Math.copySign(-2.0, Double.NEGATIVE_INFINITY));
     assertEquals(2.0, Math.copySign(-2.0, Double.POSITIVE_INFINITY));
     assertEquals(2.0, Math.copySign(-2.0, Double.NaN));
 
     assertPositiveZero(Math.copySign(0.0, 4.0));
-    assertPositiveZero(Math.copySign(negativeZero, 4.0));
+    assertPositiveZero(Math.copySign(-0.0, 4.0));
     assertNegativeZero(Math.copySign(0.0, -4.0));
-    assertNegativeZero(Math.copySign(negativeZero, -4.0));
+    assertNegativeZero(Math.copySign(-0.0, -4.0));
 
     assertPositiveZero(Math.copySign(0.0, 0.0));
-    assertPositiveZero(Math.copySign(negativeZero, 0.0));
-    assertNegativeZero(Math.copySign(0.0, negativeZero));
-    assertNegativeZero(Math.copySign(negativeZero, negativeZero));
+    assertPositiveZero(Math.copySign(-0.0, 0.0));
+    assertNegativeZero(Math.copySign(0.0, -0.0));
+    assertNegativeZero(Math.copySign(-0.0, -0.0));
 
     assertEquals(Double.POSITIVE_INFINITY, Math.copySign(Double.POSITIVE_INFINITY, 1));
     assertEquals(Double.NEGATIVE_INFINITY, Math.copySign(Double.POSITIVE_INFINITY, -1));
     assertEquals(Double.POSITIVE_INFINITY, Math.copySign(Double.NEGATIVE_INFINITY, 1));
     assertEquals(Double.NEGATIVE_INFINITY, Math.copySign(Double.NEGATIVE_INFINITY, -1));
 
-    assertEquals(Double.NaN, Math.copySign(Double.NaN, 1), 0);
-    assertEquals(Double.NaN, Math.copySign(Double.NaN, -1), 0);
+    assertNaN(Math.copySign(Double.NaN, 1));
+    assertNaN(Math.copySign(Double.NaN, -1));
   }
 
   public void testCos() {
@@ -148,12 +224,20 @@
     assertEquals(Double.POSITIVE_INFINITY, v);
   }
 
+  public void testExp() {
+    assertNaN(Math.exp(Double.NaN));
+    assertEquals(Double.POSITIVE_INFINITY, Math.exp(Double.POSITIVE_INFINITY));
+    assertPositiveZero(Math.exp(Double.NEGATIVE_INFINITY));
+    assertEquals(1, Math.exp(0));
+    assertEquals(2.718281, Math.exp(1), 0.000001);
+  }
+
   public void testExpm1() {
-    assertNegativeZero(Math.expm1(-0.));
-    assertPositiveZero(Math.expm1(0.));
+    assertNegativeZero(Math.expm1(-0.0));
+    assertPositiveZero(Math.expm1(0.0));
     assertNaN(Math.expm1(Double.NaN));
     assertEquals(Double.POSITIVE_INFINITY, Math.expm1(Double.POSITIVE_INFINITY));
-    assertEquals(-1., Math.expm1(Double.NEGATIVE_INFINITY));
+    assertEquals(-1.0, Math.expm1(Double.NEGATIVE_INFINITY));
     assertEquals(-0.632, Math.expm1(-1), 0.001);
     assertEquals(1.718, Math.expm1(1), 0.001);
   }
@@ -162,11 +246,13 @@
     double v = Math.floor(0.5);
     assertEquals(0, v, 0);
     v = Math.floor(Double.POSITIVE_INFINITY);
-    assertEquals(Double.POSITIVE_INFINITY, v, 0);
+    assertEquals(Double.POSITIVE_INFINITY, v);
     v = Math.floor(Double.NEGATIVE_INFINITY);
-    assertEquals(Double.NEGATIVE_INFINITY, v, 0);
+    assertEquals(Double.NEGATIVE_INFINITY, v);
     v = Math.floor(Double.NaN);
-    assertEquals(Double.NaN, v, 0);
+    assertNaN(v);
+    assertPositiveZero(Math.floor(0.0));
+    assertNegativeZero(Math.floor(-0.0));
 
     v = Math.floor(Double.MAX_VALUE);
     assertEquals(Double.MAX_VALUE, v, 0);
@@ -174,6 +260,38 @@
     assertEquals(-Double.MAX_VALUE, v, 0);
   }
 
+  public void testHypot() {
+    assertEquals(Double.POSITIVE_INFINITY,
+        Math.hypot(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY));
+    assertEquals(Double.POSITIVE_INFINITY,
+        Math.hypot(Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY));
+    assertEquals(Double.POSITIVE_INFINITY,
+        Math.hypot(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
+    assertEquals(Double.POSITIVE_INFINITY,
+        Math.hypot(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY));
+    assertEquals(Double.POSITIVE_INFINITY,
+        Math.hypot(0, Double.POSITIVE_INFINITY));
+    assertEquals(Double.POSITIVE_INFINITY,
+        Math.hypot(0, Double.NEGATIVE_INFINITY));
+    assertEquals(Double.POSITIVE_INFINITY,
+        Math.hypot(Double.POSITIVE_INFINITY, 0));
+    assertEquals(Double.POSITIVE_INFINITY,
+        Math.hypot(Double.NEGATIVE_INFINITY, 0));
+    assertEquals(Double.POSITIVE_INFINITY,
+        Math.hypot(Double.NaN, Double.POSITIVE_INFINITY));
+    assertEquals(Double.POSITIVE_INFINITY,
+        Math.hypot(Double.NaN, Double.NEGATIVE_INFINITY));
+    assertEquals(Double.POSITIVE_INFINITY,
+        Math.hypot(Double.POSITIVE_INFINITY, Double.NaN));
+    assertEquals(Double.POSITIVE_INFINITY,
+        Math.hypot(Double.NEGATIVE_INFINITY, Double.NaN));
+    assertNaN(Math.hypot(Double.NaN, 0));
+    assertNaN(Math.hypot(0, Double.NaN));
+
+    assertEquals(1.414213562, Math.hypot(1, 1), 1e-7);
+    assertEquals(5, Math.hypot(3, 4));
+  }
+
   public void testMax() {
     assertEquals(2d, Math.max(1d, 2d));
     assertEquals(2d, Math.max(2d, 1d));
@@ -239,15 +357,87 @@
   }
 
   public void testLog() {
+    assertNaN(Math.log(Double.NaN));
+    assertNaN(Math.log(Double.NEGATIVE_INFINITY));
+    assertNaN(Math.log(-1));
+    assertEquals(Double.POSITIVE_INFINITY, Math.log(Double.POSITIVE_INFINITY));
+    assertEquals(Double.NEGATIVE_INFINITY, Math.log(0.0));
+    assertEquals(Double.NEGATIVE_INFINITY, Math.log(-0.0));
+
     double v = Math.log(Math.E);
     assertEquals(1.0, v, 1e-15);
   }
 
   public void testLog10() {
+    assertNaN(Math.log10(Double.NaN));
+    assertNaN(Math.log10(Double.NEGATIVE_INFINITY));
+    assertNaN(Math.log10(-1));
+    assertEquals(Double.POSITIVE_INFINITY, Math.log10(Double.POSITIVE_INFINITY));
+    assertEquals(Double.NEGATIVE_INFINITY, Math.log10(0.0));
+    assertEquals(Double.NEGATIVE_INFINITY, Math.log10(-0.0));
+
     double v = Math.log10(1000.0);
     assertEquals(3.0, v, 1e-15);
   }
 
+  public void testLog1p() {
+    assertNaN(Math.log1p(Double.NaN));
+    assertNaN(Math.log1p(-2));
+    assertNaN(Math.log1p(Double.NEGATIVE_INFINITY));
+    assertEquals(Double.POSITIVE_INFINITY, Math.log1p(Double.POSITIVE_INFINITY));
+    assertEquals(Double.NEGATIVE_INFINITY, Math.log1p(-1));
+    assertPositiveZero(Math.log1p(0.0));
+    assertNegativeZero(Math.log1p(-0.0));
+
+    assertEquals(-0.693147180, Math.log1p(-0.5), 1e-7);
+    assertEquals(1.313261687, Math.log1p(Math.E), 1e-7);
+  }
+
+  public void testPow() {
+    assertEquals(1, Math.pow(2, 0.0));
+    assertEquals(1, Math.pow(2, -0.0));
+    assertEquals(2, Math.pow(2, 1));
+    assertEquals(-2, Math.pow(-2, 1));
+    assertNaN(Math.pow(1, Double.NaN));
+    assertNaN(Math.pow(Double.NaN, Double.NaN));
+    assertNaN(Math.pow(Double.NaN, 1));
+    assertEquals(1, Math.pow(Double.NaN, 0.0));
+    assertEquals(1, Math.pow(Double.NaN, -0.0));
+    assertEquals(Double.POSITIVE_INFINITY, Math.pow(1.1, Double.POSITIVE_INFINITY));
+    assertEquals(Double.POSITIVE_INFINITY, Math.pow(-1.1, Double.POSITIVE_INFINITY));
+    assertEquals(Double.POSITIVE_INFINITY, Math.pow(0.9, Double.NEGATIVE_INFINITY));
+    assertEquals(Double.POSITIVE_INFINITY, Math.pow(-0.9, Double.NEGATIVE_INFINITY));
+    assertPositiveZero(Math.pow(1.1, Double.NEGATIVE_INFINITY));
+    assertPositiveZero(Math.pow(-1.1, Double.NEGATIVE_INFINITY));
+    assertPositiveZero(Math.pow(0.9, Double.POSITIVE_INFINITY));
+    assertPositiveZero(Math.pow(-0.9, Double.POSITIVE_INFINITY));
+    assertNaN(Math.pow(1, Double.POSITIVE_INFINITY));
+    assertNaN(Math.pow(-1, Double.POSITIVE_INFINITY));
+    assertNaN(Math.pow(1, Double.NEGATIVE_INFINITY));
+    assertNaN(Math.pow(-1, Double.NEGATIVE_INFINITY));
+    assertPositiveZero(Math.pow(0.0, 1));
+    assertPositiveZero(Math.pow(Double.POSITIVE_INFINITY, -1));
+    assertEquals(Double.POSITIVE_INFINITY, Math.pow(0.0, -1));
+    assertEquals(Double.POSITIVE_INFINITY, Math.pow(Double.POSITIVE_INFINITY, 1));
+    assertPositiveZero(Math.pow(-0.0, 2));
+    assertPositiveZero(Math.pow(Double.NEGATIVE_INFINITY, -2));
+    assertNegativeZero(Math.pow(-0.0, 1));
+    assertNegativeZero(Math.pow(Double.NEGATIVE_INFINITY, -1));
+    assertEquals(Double.POSITIVE_INFINITY, Math.pow(-0.0, -2));
+    assertEquals(Double.POSITIVE_INFINITY, Math.pow(Double.NEGATIVE_INFINITY, 2));
+    assertEquals(Double.NEGATIVE_INFINITY, Math.pow(-0.0, -1));
+    assertEquals(Double.NEGATIVE_INFINITY, Math.pow(Double.NEGATIVE_INFINITY, 1));
+
+    assertEquals(9, Math.pow(3, 2));
+  }
+
+  public void testRound_float() {
+    assertEquals(1, Math.round(0.5f));
+    assertEquals(Integer.MAX_VALUE, Math.round(Float.POSITIVE_INFINITY));
+    assertEquals(Integer.MIN_VALUE, Math.round(Float.NEGATIVE_INFINITY));
+    assertEquals(0, Math.round(Float.NaN));
+  }
+
   public void testRound() {
     long v = Math.round(0.5);
     assertEquals(1L, v);
@@ -268,13 +458,13 @@
     final double twoTo52 = 1L << 52;
     // format: value to be round and expected value
     final double[] testValues = {
-        0, 0,
-        0.5, 0,
+        0.0, 0.0,
+        0.5, 0.0,
         0.75, 1,
         1.5, 2,
         1.75, 2,
-        -0, -0,
-        -0.5, -0,
+        -0.0, -0.0,
+        -0.5, -0.0,
         -1.25, -1,
         -1.5, -2,
         -2.5, -2,
@@ -292,7 +482,7 @@
         -twoTo52 - 0.5, -twoTo52,
         -twoTo52 + 0.75, -twoTo52 + 1,
         -twoTo52 - 0.75, -twoTo52 - 1,
-        Double.MIN_VALUE, 0,
+        Double.MIN_VALUE, 0.0,
         Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY,
         Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY,
         Double.NaN, Double.NaN,
@@ -310,21 +500,21 @@
 
   public void testSignum() {
     assertNaN(Math.signum(Double.NaN));
-    assertTrue(isNegativeZero(Math.signum(-0.)));
-    assertEquals(0., Math.signum(0.), 0);
-    assertEquals(-1, Math.signum(-2), 0);
-    assertEquals(1, Math.signum(2), 0);
-    assertEquals(-1., Math.signum(-Double.MAX_VALUE), 0);
-    assertEquals(1., Math.signum(Double.MAX_VALUE), 0);
-    assertEquals(-1., Math.signum(Double.NEGATIVE_INFINITY), 0);
-    assertEquals(1., Math.signum(Double.POSITIVE_INFINITY), 0);
+    assertNegativeZero(Math.signum(-0.0));
+    assertEquals(0.0, Math.signum(0.0));
+    assertEquals(-1, Math.signum(-2));
+    assertEquals(1, Math.signum(2));
+    assertEquals(-1.0, Math.signum(-Double.MAX_VALUE));
+    assertEquals(1.0, Math.signum(Double.MAX_VALUE));
+    assertEquals(-1.0, Math.signum(Double.NEGATIVE_INFINITY));
+    assertEquals(1.0, Math.signum(Double.POSITIVE_INFINITY));
   }
 
   public void testSin() {
     double v = Math.sin(0.0);
-    assertEquals(0.0, v, 1e-7);
+    assertPositiveZero(v);
     v = Math.sin(-0.0);
-    assertEquals(-0.0, v, 1e-7);
+    assertNegativeZero(v);
     v = Math.sin(Math.PI * .5);
     assertEquals(1.0, v, 1e-7);
     v = Math.sin(Math.PI);
@@ -341,7 +531,9 @@
 
   public void testSinh() {
     double v = Math.sinh(0.0);
-    assertEquals(0.0, v);
+    assertPositiveZero(v);
+    v = Math.sinh(-0.0);
+    assertNegativeZero(v);
     v = Math.sinh(1.0);
     assertEquals(1.175201193, v, 1e-7);
     v = Math.sinh(-1.0);
@@ -352,15 +544,24 @@
     assertEquals(Double.NEGATIVE_INFINITY, v);
     v = Math.sinh(Double.POSITIVE_INFINITY);
     assertEquals(Double.POSITIVE_INFINITY, v);
-    v = Math.sinh(-0.0);
-    assertEquals(-0.0, v);
+  }
+
+  public void testSqrt() {
+    assertNaN(Math.sqrt(Double.NaN));
+    assertNaN(Math.sqrt(Double.NEGATIVE_INFINITY));
+    assertNaN(Math.sqrt(-1));
+    assertEquals(Double.POSITIVE_INFINITY, Math.sqrt(Double.POSITIVE_INFINITY));
+    assertPositiveZero(Math.sqrt(0.0));
+    assertNegativeZero(Math.sqrt(-0.0));
+
+    assertEquals(1.732050807, Math.sqrt(3), 1e-7);
   }
 
   public void testTan() {
     double v = Math.tan(0.0);
-    assertEquals(0.0, v, 1e-7);
+    assertPositiveZero(v);
     v = Math.tan(-0.0);
-    assertEquals(-0.0, v, 1e-7);
+    assertNegativeZero(v);
     v = Math.tan(Double.NaN);
     assertNaN(v);
     v = Math.tan(Double.NEGATIVE_INFINITY);
@@ -371,7 +572,9 @@
 
   public void testTanh() {
     double v = Math.tanh(0.0);
-    assertEquals(0.0, v);
+    assertPositiveZero(v);
+    v = Math.tanh(-0.0);
+    assertNegativeZero(v);
     v = Math.tanh(1.0);
     assertEquals(0.761594155, v, 1e-7);
     v = Math.tanh(-1.0);
@@ -382,11 +585,17 @@
     assertEquals(-1.0, v, 1e-7);
     v = Math.tanh(Double.POSITIVE_INFINITY);
     assertEquals(1.0, v, 1e-7);
-    v = Math.tanh(-0.0);
-    assertEquals(-0.0, v);
   }
 
   public void testScalb() {
+    for (int scaleFactor = -32; scaleFactor <= 32; scaleFactor++) {
+      assertNaN(Math.scalb(Double.NaN, scaleFactor));
+      assertEquals(Double.POSITIVE_INFINITY, Math.scalb(Double.POSITIVE_INFINITY, scaleFactor));
+      assertEquals(Double.NEGATIVE_INFINITY, Math.scalb(Double.NEGATIVE_INFINITY, scaleFactor));
+      assertPositiveZero(Math.scalb(0.0, scaleFactor));
+      assertNegativeZero(Math.scalb(-0.0, scaleFactor));
+    }
+
     assertEquals(40.0d, Math.scalb(5d, 3));
     assertEquals(40.0f, Math.scalb(5f, 3));