summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2015-04-09 10:35:07 -0600
committerGregory Nutt <gnutt@nuttx.org>2015-04-09 10:35:07 -0600
commit139cf5a68a77007992d23eb36442206bdea796f7 (patch)
treed29babbd351883e04d86d54cfec85a92a30de7b7
parent0741880a14fd021477a20922f81bd4b79bb495e4 (diff)
downloadpx4-nuttx-139cf5a68a77007992d23eb36442206bdea796f7.tar.gz
px4-nuttx-139cf5a68a77007992d23eb36442206bdea796f7.tar.bz2
px4-nuttx-139cf5a68a77007992d23eb36442206bdea796f7.zip
Fixes to asinh(), atanh(), and sinh(): The 'basic' expansions all exhibited bad cancellation errors near zero (<= 1E-10). This can be easily seen e.g. with x = 1E-30, the results are all zero though they should be extremely close to x. The cutoff values (1E-5, 1E-9) are chosen so that the next term in the Taylor series is negligible (for double). Functions could maybe be optimized to use only first term (x) and a smaller cutoff, just bigger than where the cancellation occurs.
-rw-r--r--nuttx/libc/math/lib_asinh.c16
-rw-r--r--nuttx/libc/math/lib_atanh.c17
-rw-r--r--nuttx/libc/math/lib_sinh.c21
3 files changed, 49 insertions, 5 deletions
diff --git a/nuttx/libc/math/lib_asinh.c b/nuttx/libc/math/lib_asinh.c
index 7b573fcdd..5a30ac1aa 100644
--- a/nuttx/libc/math/lib_asinh.c
+++ b/nuttx/libc/math/lib_asinh.c
@@ -49,6 +49,20 @@
#ifdef CONFIG_HAVE_DOUBLE
double asinh(double x)
{
- return log(x + sqrt(x * x + 1));
+ double y;
+ double z = x * x;
+
+ if (z < 1E-9)
+ {
+ /* x - 1/6 * x^3 + 3/40 * x^5 - 5/112 * x^7 + ... */
+
+ y = x * (1 - z / 6.0);
+ }
+ else
+ {
+ y = log(x + sqrt(z + 1));
+ }
+
+ return y;
}
#endif
diff --git a/nuttx/libc/math/lib_atanh.c b/nuttx/libc/math/lib_atanh.c
index 9932a5e9b..396e80852 100644
--- a/nuttx/libc/math/lib_atanh.c
+++ b/nuttx/libc/math/lib_atanh.c
@@ -49,6 +49,21 @@
#ifdef CONFIG_HAVE_DOUBLE
double atanh(double x)
{
- return 0.5 * log((1 + x) / (1 - x));
+ double y;
+
+ if (fabs(x) < 1E-5)
+ {
+ double z = x * x;
+
+ /* x + 1/3 * x^3 + 1/5 * x^5 + 1/7 * x^7 + ... */
+
+ y = x * (1 + z / 3.0);
+ }
+ else
+ {
+ y = log((1 + x) / (1 - x)) / 2.0;
+ }
+
+ return y;
}
#endif
diff --git a/nuttx/libc/math/lib_sinh.c b/nuttx/libc/math/lib_sinh.c
index da79e7cfd..714a52816 100644
--- a/nuttx/libc/math/lib_sinh.c
+++ b/nuttx/libc/math/lib_sinh.c
@@ -3,7 +3,7 @@
*
* This file is a part of NuttX:
*
- * Copyright (C) 2012 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2012, 2015 Gregory Nutt. All rights reserved.
* Ported by: Darcy Gong
*
* It derives from the Rhombs OS math library by Nick Johnson which has
@@ -41,7 +41,22 @@
#ifdef CONFIG_HAVE_DOUBLE
double sinh(double x)
{
- x = exp(x);
- return ((x - (1.0 / x)) / 2.0);
+ double y;
+ double z;
+
+ if (fabs(x) < 1E-5)
+ {
+ /* x + 1/3! * x^3 + 1/5! * x^5 + 1/7! * x^7 + ... */
+
+ z = x * x;
+ y = x * (1.0 + z / 6.0);
+ }
+ else
+ {
+ z = exp(x);
+ y = (z - 1.0 / z) / 2.0;
+ }
+
+ return y;
}
#endif