summaryrefslogtreecommitdiff
path: root/lib/mlibc/options/ansi/musl-generic-math/sinh.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/mlibc/options/ansi/musl-generic-math/sinh.c')
-rw-r--r--lib/mlibc/options/ansi/musl-generic-math/sinh.c39
1 files changed, 39 insertions, 0 deletions
diff --git a/lib/mlibc/options/ansi/musl-generic-math/sinh.c b/lib/mlibc/options/ansi/musl-generic-math/sinh.c
new file mode 100644
index 0000000..00022c4
--- /dev/null
+++ b/lib/mlibc/options/ansi/musl-generic-math/sinh.c
@@ -0,0 +1,39 @@
+#include "libm.h"
+
+/* sinh(x) = (exp(x) - 1/exp(x))/2
+ * = (exp(x)-1 + (exp(x)-1)/exp(x))/2
+ * = x + x^3/6 + o(x^5)
+ */
+double sinh(double x)
+{
+ union {double f; uint64_t i;} u = {.f = x};
+ uint32_t w;
+ double t, h, absx;
+
+ h = 0.5;
+ if (u.i >> 63)
+ h = -h;
+ /* |x| */
+ u.i &= (uint64_t)-1/2;
+ absx = u.f;
+ w = u.i >> 32;
+
+ /* |x| < log(DBL_MAX) */
+ if (w < 0x40862e42) {
+ t = expm1(absx);
+ if (w < 0x3ff00000) {
+ if (w < 0x3ff00000 - (26<<20))
+ /* note: inexact and underflow are raised by expm1 */
+ /* note: this branch avoids spurious underflow */
+ return x;
+ return h*(2*t - t*t/(t+1));
+ }
+ /* note: |x|>log(0x1p26)+eps could be just h*exp(x) */
+ return h*(t + t/(t+1));
+ }
+
+ /* |x| > log(DBL_MAX) or nan */
+ /* note: the result is stored to handle overflow */
+ t = 2*h*__expo2(absx);
+ return t;
+}