Fix implementation of Math.sinh and Math.tanh (external issue 4991)

Review at http://gwt-code-reviews.appspot.com/602801

Review by: jat@google.com

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@8243 8db76d5a-ed1c-0410-87a9-c151d255dfc7
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 3026b93..a9e8c11 100644
--- a/user/super/com/google/gwt/emul/java/lang/Math.java
+++ b/user/super/com/google/gwt/emul/java/lang/Math.java
@@ -27,11 +27,11 @@
   private static final double PI_UNDER_180 = 180.0 / PI;
 
   public static double abs(double x) {
-    return x < 0 ? -x : x;
+    return (x <= 0.0) ? 0.0 - x : x;
   }
 
   public static float abs(float x) {
-    return x < 0 ? -x : x;
+    return (x <= 0.0F) ? 0.0F - x : x;
   }
 
   public static int abs(int x) {
@@ -253,7 +253,7 @@
   }-*/;
 
   public static native double sinh(double x) /*-{
-    return Math.sinh(x);
+    return (Math.exp(x) - Math.exp(-x)) / 2.0;
   }-*/;
 
   public static native double sqrt(double x) /*-{
@@ -265,7 +265,11 @@
   }-*/;
 
   public static native double tanh(double x) /*-{
-    return Math.tanh(x);
+    if (x == Infinity) {
+      return 1.0;
+    }
+    var 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 81f41b4..4d5b99d 100644
--- a/user/test/com/google/gwt/emultest/java/lang/MathTest.java
+++ b/user/test/com/google/gwt/emultest/java/lang/MathTest.java
@@ -30,6 +30,23 @@
     return "com.google.gwt.emultest.EmulSuite";
   }
   
+  public void testAbs() {
+    double v = Math.abs(-1.0);
+    assertEquals(1.0, v);
+    v = Math.abs(1.0);
+    assertEquals(1.0, v);
+    v = Math.abs(-0.0);
+    assertEquals(0.0, v);
+    v = Math.abs(0.0);
+    assertEquals(0.0, v);
+    v = Math.abs(Double.NEGATIVE_INFINITY);
+    assertEquals(Double.POSITIVE_INFINITY, v);
+    v = Math.abs(Double.POSITIVE_INFINITY);
+    assertEquals(Double.POSITIVE_INFINITY, v);
+    v = Math.abs(Double.NaN);
+    assertTrue(Double.isNaN(v));
+  }
+  
   public void testCbrt() {
     double v = Math.cbrt(1000.0);
     assertEquals(10.0, v, 1e-7);
@@ -38,12 +55,35 @@
   public void testCos() {
     double v = Math.cos(0.0);
     assertEquals(1.0, v, 1e-7);
+    v = Math.cos(-0.0);
+    assertEquals(1.0, v, 1e-7);
     v = Math.cos(Math.PI * .5);
     assertEquals(0.0, v, 1e-7);
     v = Math.cos(Math.PI);
     assertEquals(-1.0, v, 1e-7);
     v = Math.cos(Math.PI * 1.5);
     assertEquals(0.0, v, 1e-7);
+    v = Math.cos(Double.NaN);
+    assertTrue(Double.isNaN(v));
+    v = Math.cos(Double.NEGATIVE_INFINITY);
+    assertTrue(Double.isNaN(v));
+    v = Math.cos(Double.POSITIVE_INFINITY);
+    assertTrue(Double.isNaN(v));
+  }
+  
+  public void testCosh() {
+    double v = Math.cosh(0.0);
+    assertEquals(1.0, v, 1e-7);
+    v = Math.cosh(1.0);
+    assertEquals(1.5430806348, v, 1e-7);
+    v = Math.cosh(-1.0);
+    assertEquals(1.5430806348, v, 1e-7);
+    v = Math.cosh(Double.NaN);
+    assertTrue(Double.isNaN(v));
+    v = Math.cosh(Double.NEGATIVE_INFINITY);
+    assertEquals(Double.POSITIVE_INFINITY, v);
+    v = Math.cosh(Double.POSITIVE_INFINITY);
+    assertEquals(Double.POSITIVE_INFINITY, v);
   }
 
   public void testLog() {
@@ -59,11 +99,66 @@
   public void testSin() {
     double v = Math.sin(0.0);
     assertEquals(0.0, v, 1e-7);
+    v = Math.sin(-0.0);
+    assertEquals(-0.0, v, 1e-7);
     v = Math.sin(Math.PI * .5);
     assertEquals(1.0, v, 1e-7);
     v = Math.sin(Math.PI);
     assertEquals(0.0, v, 1e-7);
     v = Math.sin(Math.PI * 1.5);
     assertEquals(-1.0, v, 1e-7);
+    v = Math.sin(Double.NaN);
+    assertTrue(Double.isNaN(v));
+    v = Math.sin(Double.NEGATIVE_INFINITY);
+    assertTrue(Double.isNaN(v));
+    v = Math.sin(Double.POSITIVE_INFINITY);
+    assertTrue(Double.isNaN(v));
+  }
+  
+  public void testSinh() {
+    double v = Math.sinh(0.0);
+    assertEquals(0.0, v);
+    v = Math.sinh(1.0);
+    assertEquals(1.175201193, v, 1e-7);
+    v = Math.sinh(-1.0);
+    assertEquals(-1.175201193, v, 1e-7);
+    v = Math.sinh(Double.NaN);
+    assertTrue(Double.isNaN(v));
+    v = Math.sinh(Double.NEGATIVE_INFINITY);
+    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 testTan() {
+    double v = Math.tan(0.0);
+    assertEquals(0.0, v, 1e-7);
+    v = Math.tan(-0.0);
+    assertEquals(-0.0, v, 1e-7);
+    v = Math.tan(Double.NaN);
+    assertTrue(Double.isNaN(v));
+    v = Math.tan(Double.NEGATIVE_INFINITY);
+    assertTrue(Double.isNaN(v));
+    v = Math.tan(Double.POSITIVE_INFINITY);
+    assertTrue(Double.isNaN(v));
+  }
+  
+  public void testTanh() {
+    double v = Math.tanh(0.0);
+    assertEquals(0.0, v);
+    v = Math.tanh(1.0);
+    assertEquals(0.761594155, v, 1e-7);
+    v = Math.tanh(-1.0);
+    assertEquals(-0.761594155, v, 1e-7);
+    v = Math.tanh(Double.NaN);
+    assertTrue(Double.isNaN(v));
+    v = Math.tanh(Double.NEGATIVE_INFINITY);
+    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);
   }
 }