/ tanh.s (emx+gcc) -- Copyright (c) 1992-1993 by Eberhard Mattes

#include <libm.h>

        .globl  FUN(tanh)

        .text

        .align  2, 0x90

/ double tanh (double x)

#define cw1      0(%esp)
#define cw2      2(%esp)
/define ret_addr 4(%esp)
#define x        8(%esp)

/ tanh(x) = (t-1.0) / (t+1.0) with t = exp (2.0 * x)

DEF(tanh)
        subl    $4, %esp                / space for control words
        FLD     x                       / x
        fmull   __const_TWO             / 2x
        fldl2e                          / log2 (e)
        fmulp                           / y := 2x * log2 (e)
        fstcww  cw1
        movw    cw1, %ax
        andw    $0xf3ff, %ax
        orw     $0x0400, %ax            / round down towards -inf
        movw    %ax, cw2
        fldcww  cw2      
        fld     %st                     / y, y
        frndint                         / int (y), y
        fldcww  cw1
        fxch    %st(1)                  / y, int (y)
        fsub    %st(1), %st             / frac (y), int (y)
        f2xm1                           / 2 ^ frac (y) - 1, int (y)
        faddl   __const_ONE             / 2 ^ frac (y), int (y)
        fscale                          / 2 ^ frac (y) * 2 ^ int (y), int (y)
        fstp    %st(1)                  / 2 ^ frac (y) * 2 ^ int (y)
        fld     %st                     / t, t
        faddl   __const_ONE             / t+1, t
        fxch    %st(1)                  / t, t+1
        fsubl   __const_ONE             / t-1, t+1
        fdivp                           / (t-1)/(t+1)
        CONV(x)                         / convert to double
        addl    $4, %esp                / Remove control words
        _xam
        j_inf   1f
        ret

        .align  2, 0x90
1:      SETERRNO($ERANGE)
        ret
