text: // Copyright (c) Microsoft Corporation. All rights reserved.
  // Licensed under the MIT License.
  
  //-----------------------------------------------------------------------------
  //  Package Title  ratpak
  //  File           itransh.c
  //  Copyright      (C) 1995-97 Microsoft
  //  Date           01-16-95
  //
  //
  //  Description
  //
  //    Contains inverse hyperbolic sin, cos, and tan functions.
  //
  //  Special Information
  //
  //
  //-----------------------------------------------------------------------------
  #include "ratpak.h"
  
  //-----------------------------------------------------------------------------
  //
  //  FUNCTION: asinhrat
  //
  //  ARGUMENTS:  x PRAT representation of number to take the inverse
  //    hyperbolic sine of
  //  RETURN: asinh of x in PRAT form.
  //
  //  EXPLANATION: This uses Taylor series
  //
  //    n
  //   ___                                                   2 2
  //   \  ]                                           -(2j+1) X
  //    \   thisterm  ; where thisterm   = thisterm  * ---------
  //    /           j                 j+1          j   (2j+2)*(2j+3)
  //   /__]
  //   j=0
  //
  //   thisterm  = X ;  and stop when thisterm < precision used.
  //           0                              n
  //
  //   For abs(x) < .85, and
  //
  //   asinh(x) = log(x+sqrt(x^2+1))
  //
  //   For abs(x) >= .85
  //
  //-----------------------------------------------------------------------------
  
  void asinhrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision)
  
  {
      PRAT neg_pt_eight_five = nullptr;
  
      DUPRAT(neg_pt_eight_five, pt_eight_five);
      neg_pt_eight_five->pp->sign *= -1;
      if (rat_gt(*px, pt_eight_five, precision) || rat_lt(*px, neg_pt_eight_five, precision))
      {
          PRAT ptmp = nullptr;
          DUPRAT(ptmp, (*px));
          mulrat(&ptmp, *px, precision);
          addrat(&ptmp, rat_one, precision);
          rootrat(&ptmp, rat_two, radix, precision);
          addrat(px, ptmp, precision);
          lograt(px, precision);
          destroyrat(ptmp);
      }
      else
      {
          CREATETAYLOR();
          xx->pp->sign *= -1;
  
          DUPRAT(pret, (*px));
          DUPRAT(thisterm, (*px));
  
          DUPNUM(n2, num_one);
  
          do
          {
              NEXTTERM(xx, MULNUM(n2) MULNUM(n2) INC(n2) DIVNUM(n2) INC(n2) DIVNUM(n2), precision);
          } while (!SMALL_ENOUGH_RAT(thisterm, precision));
  
          DESTROYTAYLOR();
      }
      destroyrat(neg_pt_eight_five);
  }
  
  //-----------------------------------------------------------------------------
  //
  //  FUNCTION: acoshrat
  //
  //  ARGUMENTS:  x PRAT representation of number to take the inverse
  //    hyperbolic cose of
  //  RETURN: acosh of x in PRAT form.
  //
  //  EXPLANATION: This uses
  //
  //   acosh(x)=ln(x+sqrt(x^2-1))
  //
  //   For x >= 1
  //
  //-----------------------------------------------------------------------------
  
  void acoshrat(_Inout_ PRAT* px, uint32_t radix, int32_t precision)
  
  {
      if (rat_lt(*px, rat_one, precision))
      {
          throw CALC_E_DOMAIN;
      }
      else
      {
          PRAT ptmp = nullptr;
          DUPRAT(ptmp, (*px));
          mulrat(&ptmp, *px, precision);
          subrat(&ptmp, rat_one, precision);
          rootrat(&ptmp, rat_two, radix, precision);
          addrat(px, ptmp, precision);
          lograt(px, precision);
          destroyrat(ptmp);
      }
  }
  
  //-----------------------------------------------------------------------------
  //
  //  FUNCTION: atanhrat
  //
  //  ARGUMENTS:  x PRAT representation of number to take the inverse
  //              hyperbolic tangent of
  //
  //  RETURN: atanh of x in PRAT form.
  //
  //  EXPLANATION: This uses
  //
  //             1     x+1
  //  atanh(x) = -*ln(----)
  //             2     x-1
  //
  //-----------------------------------------------------------------------------
  
  void atanhrat(_Inout_ PRAT* px, int32_t precision)
  
  {
      PRAT ptmp = nullptr;
      DUPRAT(ptmp, (*px));
      subrat(&ptmp, rat_one, precision);
      addrat(px, rat_one, precision);
      divrat(px, ptmp, precision);
      (*px)->pp->sign *= -1;
      lograt(px, precision);
      divrat(px, rat_two, precision);
      destroyrat(ptmp);
  }
  