You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ah...@apache.org on 2019/12/07 02:27:46 UTC
[commons-numbers] 04/04: Update tanh() to perform edge checks on
twice the imaginary value.
This is an automated email from the ASF dual-hosted git repository.
aherbert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-numbers.git
commit 69a69afd8e4c5bbe4b3eef60acbe2d9637d5cfa7
Author: Alex Herbert <ah...@apache.org>
AuthorDate: Sat Dec 7 02:25:41 2019 +0000
Update tanh() to perform edge checks on twice the imaginary value.
This matches the reference test result.
---
.../apache/commons/numbers/complex/Complex.java | 33 ++++++++++++++--------
.../commons/numbers/complex/CReferenceTest.java | 18 ++++++------
2 files changed, 31 insertions(+), 20 deletions(-)
diff --git a/commons-numbers-complex/src/main/java/org/apache/commons/numbers/complex/Complex.java b/commons-numbers-complex/src/main/java/org/apache/commons/numbers/complex/Complex.java
index aa2bc2a..f8af35e 100644
--- a/commons-numbers-complex/src/main/java/org/apache/commons/numbers/complex/Complex.java
+++ b/commons-numbers-complex/src/main/java/org/apache/commons/numbers/complex/Complex.java
@@ -1785,27 +1785,38 @@ public final class Complex implements Serializable {
* @return the hyperbolic tangent of the complex number
*/
private static Complex tanh(double real, double imaginary, ComplexConstructor constructor) {
- // TODO: Should these checks be made on real2 and imaginary2?
- // Compare to other library implementations.
- //
// Math.cos and Math.sin return NaN for infinity.
- // Math.cosh returns positive infinity for infinity.
- // Math.sinh returns the input infinity for infinity.
+ // Perform edge-condition checks on the twice the imaginary value.
+ // This handles very big imaginary numbers as infinite.
+
+ final double imaginary2 = 2 * imaginary;
if (Double.isFinite(real)) {
- if (Double.isFinite(imaginary)) {
- final double real2 = 2 * real;
- final double imaginary2 = 2 * imaginary;
+ if (Double.isFinite(imaginary2)) {
+ double real2 = 2 * real;
+
+ // Math.cosh returns positive infinity for infinity.
+ // cosh -> inf
final double d = Math.cosh(real2) + Math.cos(imaginary2);
- return constructor.create(Math.sinh(real2) / d,
+ // Math.sinh returns the input infinity for infinity.
+ // sinh -> inf for positive x; else -inf
+ final double sinhRe2 = Math.sinh(real2);
+
+ // Avoid inf / inf
+ if (Double.isInfinite(sinhRe2) && Double.isInfinite(d)) {
+ // Fall-through to the result if infinite
+ return constructor.create(Math.copySign(1, real), Math.copySign(0, Math.sin(imaginary2)));
+ }
+ return constructor.create(sinhRe2 / d,
Math.sin(imaginary2) / d);
}
+ // imaginary is infinite or NaN
return NAN;
}
if (Double.isInfinite(real)) {
- if (Double.isFinite(imaginary)) {
- return constructor.create(Math.copySign(1, real), Math.copySign(0, Math.sin(2 * imaginary)));
+ if (Double.isFinite(imaginary2)) {
+ return constructor.create(Math.copySign(1, real), Math.copySign(0, Math.sin(imaginary2)));
}
// imaginary is infinite or NaN
return constructor.create(Math.copySign(1, real), Math.copySign(0, imaginary));
diff --git a/commons-numbers-complex/src/test/java/org/apache/commons/numbers/complex/CReferenceTest.java b/commons-numbers-complex/src/test/java/org/apache/commons/numbers/complex/CReferenceTest.java
index 2c268f0..5ec32da 100644
--- a/commons-numbers-complex/src/test/java/org/apache/commons/numbers/complex/CReferenceTest.java
+++ b/commons-numbers-complex/src/test/java/org/apache/commons/numbers/complex/CReferenceTest.java
@@ -473,11 +473,11 @@ public class CReferenceTest {
@Test
public void testTanh() {
-// assertComplex(-1e+308, 0.0, Complex::tanh, -1, -0.0);
-// assertComplex(-1e+308, 0.5, Complex::tanh, -1, 0.0);
-// assertComplex(-1e+308, 1, Complex::tanh, -1, 0.0);
-// assertComplex(-1e+308, 2, Complex::tanh, -1, 0.0);
-// assertComplex(-1e+308, 1e+308, Complex::tanh, nan, nan);
+ assertComplex(-1e+308, 0.0, Complex::tanh, -1, -0.0);
+ assertComplex(-1e+308, 0.5, Complex::tanh, -1, 0.0);
+ assertComplex(-1e+308, 1, Complex::tanh, -1, 0.0);
+ assertComplex(-1e+308, 2, Complex::tanh, -1, 0.0);
+ assertComplex(-1e+308, 1e+308, Complex::tanh, nan, nan);
assertComplex(-2, 0.0, Complex::tanh, -0.9640275800758169, 0.0);
assertComplex(-2, 0.5, Complex::tanh, -0.97994084996173814, 0.030215987322877575);
assertComplex(-2, 1, Complex::tanh, -1.0147936161466335, 0.033812826079896691);
@@ -518,10 +518,10 @@ public class CReferenceTest {
assertComplex(2, 1, Complex::tanh, 1.0147936161466335, 0.033812826079896691);
assertComplex(2, 2, Complex::tanh, 1.0238355945704727, -0.028392952868232287);
assertComplex(2, 1e+308, Complex::tanh, nan, nan);
-// assertComplex(1e+308, 0.0, Complex::tanh, 1, -0.0);
-// assertComplex(1e+308, 0.5, Complex::tanh, 1, 0.0);
-// assertComplex(1e+308, 1, Complex::tanh, 1, 0.0);
-// assertComplex(1e+308, 2, Complex::tanh, 1, 0.0);
+ assertComplex(1e+308, 0.0, Complex::tanh, 1, -0.0);
+ assertComplex(1e+308, 0.5, Complex::tanh, 1, 0.0);
+ assertComplex(1e+308, 1, Complex::tanh, 1, 0.0);
+ assertComplex(1e+308, 2, Complex::tanh, 1, 0.0);
assertComplex(1e+308, 1e+308, Complex::tanh, nan, nan);
}