Blame src/asinh.c

Packit fbef6a
/* mpfr_asinh -- inverse hyperbolic sine
Packit fbef6a
Packit fbef6a
Copyright 2001-2017 Free Software Foundation, Inc.
Packit fbef6a
Contributed by the AriC and Caramba projects, INRIA.
Packit fbef6a
Packit fbef6a
This file is part of the GNU MPFR Library.
Packit fbef6a
Packit fbef6a
The GNU MPFR Library is free software; you can redistribute it and/or modify
Packit fbef6a
it under the terms of the GNU Lesser General Public License as published by
Packit fbef6a
the Free Software Foundation; either version 3 of the License, or (at your
Packit fbef6a
option) any later version.
Packit fbef6a
Packit fbef6a
The GNU MPFR Library is distributed in the hope that it will be useful, but
Packit fbef6a
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
Packit fbef6a
or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
Packit fbef6a
License for more details.
Packit fbef6a
Packit fbef6a
You should have received a copy of the GNU Lesser General Public License
Packit fbef6a
along with the GNU MPFR Library; see the file COPYING.LESSER.  If not, see
Packit fbef6a
http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
Packit fbef6a
51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
Packit fbef6a
Packit fbef6a
#define MPFR_NEED_LONGLONG_H
Packit fbef6a
#include "mpfr-impl.h"
Packit fbef6a
Packit fbef6a
/* The computation of asinh is done by  *
Packit fbef6a
 *    asinh = ln(x + sqrt(x^2 + 1))     */
Packit fbef6a
Packit fbef6a
int
Packit fbef6a
mpfr_asinh (mpfr_ptr y, mpfr_srcptr x, mpfr_rnd_t rnd_mode)
Packit fbef6a
{
Packit fbef6a
  int inexact;
Packit fbef6a
  int signx, neg;
Packit fbef6a
  mpfr_prec_t Ny, Nt;
Packit fbef6a
  mpfr_t t; /* auxiliary variables */
Packit fbef6a
  mpfr_exp_t err;
Packit fbef6a
  MPFR_SAVE_EXPO_DECL (expo);
Packit fbef6a
  MPFR_ZIV_DECL (loop);
Packit fbef6a
Packit fbef6a
  MPFR_LOG_FUNC (
Packit fbef6a
    ("x[%Pu]=%.*Rg rnd=%d", mpfr_get_prec (x), mpfr_log_prec, x, rnd_mode),
Packit fbef6a
    ("y[%Pu]=%.*Rg inexact=%d", mpfr_get_prec (y), mpfr_log_prec, y,
Packit fbef6a
     inexact));
Packit fbef6a
Packit fbef6a
  if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (x)))
Packit fbef6a
    {
Packit fbef6a
      if (MPFR_IS_NAN (x))
Packit fbef6a
        {
Packit fbef6a
          MPFR_SET_NAN (y);
Packit fbef6a
          MPFR_RET_NAN;
Packit fbef6a
        }
Packit fbef6a
      else if (MPFR_IS_INF (x))
Packit fbef6a
        {
Packit fbef6a
          MPFR_SET_INF (y);
Packit fbef6a
          MPFR_SET_SAME_SIGN (y, x);
Packit fbef6a
          MPFR_RET (0);
Packit fbef6a
        }
Packit fbef6a
      else /* x is necessarily 0 */
Packit fbef6a
        {
Packit fbef6a
          MPFR_ASSERTD (MPFR_IS_ZERO (x));
Packit fbef6a
          MPFR_SET_ZERO (y);   /* asinh(0) = 0 */
Packit fbef6a
          MPFR_SET_SAME_SIGN (y, x);
Packit fbef6a
          MPFR_RET (0);
Packit fbef6a
        }
Packit fbef6a
    }
Packit fbef6a
Packit fbef6a
  /* asinh(x) = x - x^3/6 + ... so the error is < 2^(3*EXP(x)-2) */
Packit fbef6a
  MPFR_FAST_COMPUTE_IF_SMALL_INPUT (y, x, -2 * MPFR_GET_EXP (x), 2, 0,
Packit fbef6a
                                    rnd_mode, {});
Packit fbef6a
Packit fbef6a
  Ny = MPFR_PREC (y);   /* Precision of output variable */
Packit fbef6a
Packit fbef6a
  signx = MPFR_SIGN (x);
Packit fbef6a
  neg = MPFR_IS_NEG (x);
Packit fbef6a
Packit fbef6a
  /* General case */
Packit fbef6a
Packit fbef6a
  /* compute the precision of intermediary variable */
Packit fbef6a
  /* the optimal number of bits : see algorithms.tex */
Packit fbef6a
  Nt = Ny + 4 + MPFR_INT_CEIL_LOG2 (Ny);
Packit fbef6a
Packit fbef6a
  MPFR_SAVE_EXPO_MARK (expo);
Packit fbef6a
Packit fbef6a
  /* initialize intermediary variables */
Packit fbef6a
  mpfr_init2 (t, Nt);
Packit fbef6a
Packit fbef6a
  /* First computation of asinh */
Packit fbef6a
  MPFR_ZIV_INIT (loop, Nt);
Packit fbef6a
  for (;;)
Packit fbef6a
    {
Packit fbef6a
      /* compute asinh */
Packit fbef6a
      mpfr_mul (t, x, x, MPFR_RNDD);                    /* x^2 */
Packit fbef6a
      mpfr_add_ui (t, t, 1, MPFR_RNDD);                 /* x^2+1 */
Packit fbef6a
      mpfr_sqrt (t, t, MPFR_RNDN);                      /* sqrt(x^2+1) */
Packit fbef6a
      (neg ? mpfr_sub : mpfr_add) (t, t, x, MPFR_RNDN); /* sqrt(x^2+1)+x */
Packit fbef6a
      mpfr_log (t, t, MPFR_RNDN);                       /* ln(sqrt(x^2+1)+x)*/
Packit fbef6a
Packit fbef6a
      if (MPFR_LIKELY (MPFR_IS_PURE_FP (t)))
Packit fbef6a
        {
Packit fbef6a
          /* error estimate -- see algorithms.tex */
Packit fbef6a
          err = Nt - (MAX (4 - MPFR_GET_EXP (t), 0) + 1);
Packit fbef6a
          if (MPFR_LIKELY (MPFR_IS_ZERO (t)
Packit fbef6a
                           || MPFR_CAN_ROUND (t, err, Ny, rnd_mode)))
Packit fbef6a
            break;
Packit fbef6a
        }
Packit fbef6a
Packit fbef6a
      /* actualisation of the precision */
Packit fbef6a
      MPFR_ZIV_NEXT (loop, Nt);
Packit fbef6a
      mpfr_set_prec (t, Nt);
Packit fbef6a
    }
Packit fbef6a
  MPFR_ZIV_FREE (loop);
Packit fbef6a
Packit fbef6a
  inexact = mpfr_set4 (y, t, rnd_mode, signx);
Packit fbef6a
Packit fbef6a
  mpfr_clear (t);
Packit fbef6a
Packit fbef6a
  MPFR_SAVE_EXPO_FREE (expo);
Packit fbef6a
  return mpfr_check_range (y, inexact, rnd_mode);
Packit fbef6a
}