Blame lib/printf-frexp.c

Packit Service a2489d
/* Split a double into fraction and mantissa, for hexadecimal printf.
Packit Service a2489d
   Copyright (C) 2007, 2009-2018 Free Software Foundation, Inc.
Packit Service a2489d
Packit Service a2489d
   This program is free software: you can redistribute it and/or modify
Packit Service a2489d
   it under the terms of the GNU General Public License as published by
Packit Service a2489d
   the Free Software Foundation; either version 3 of the License, or
Packit Service a2489d
   (at your option) any later version.
Packit Service a2489d
Packit Service a2489d
   This program is distributed in the hope that it will be useful,
Packit Service a2489d
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service a2489d
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service a2489d
   GNU General Public License for more details.
Packit Service a2489d
Packit Service a2489d
   You should have received a copy of the GNU General Public License
Packit Service a2489d
   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
Packit Service a2489d
Packit Service a2489d
#if ! defined USE_LONG_DOUBLE
Packit Service a2489d
# include <config.h>
Packit Service a2489d
#endif
Packit Service a2489d
Packit Service a2489d
/* Specification.  */
Packit Service a2489d
#ifdef USE_LONG_DOUBLE
Packit Service a2489d
# include "printf-frexpl.h"
Packit Service a2489d
#else
Packit Service a2489d
# include "printf-frexp.h"
Packit Service a2489d
#endif
Packit Service a2489d
Packit Service a2489d
#include <float.h>
Packit Service a2489d
#include <math.h>
Packit Service a2489d
#ifdef USE_LONG_DOUBLE
Packit Service a2489d
# include "fpucw.h"
Packit Service a2489d
#endif
Packit Service a2489d
Packit Service a2489d
/* This file assumes FLT_RADIX = 2.  If FLT_RADIX is a power of 2 greater
Packit Service a2489d
   than 2, or not even a power of 2, some rounding errors can occur, so that
Packit Service a2489d
   then the returned mantissa is only guaranteed to be <= 2.0, not < 2.0.  */
Packit Service a2489d
Packit Service a2489d
#ifdef USE_LONG_DOUBLE
Packit Service a2489d
# define FUNC printf_frexpl
Packit Service a2489d
# define DOUBLE long double
Packit Service a2489d
# define MIN_EXP LDBL_MIN_EXP
Packit Service a2489d
# if HAVE_FREXPL_IN_LIBC && HAVE_LDEXPL_IN_LIBC
Packit Service a2489d
#  define USE_FREXP_LDEXP
Packit Service a2489d
#  define FREXP frexpl
Packit Service a2489d
#  define LDEXP ldexpl
Packit Service a2489d
# endif
Packit Service a2489d
# define DECL_ROUNDING DECL_LONG_DOUBLE_ROUNDING
Packit Service a2489d
# define BEGIN_ROUNDING() BEGIN_LONG_DOUBLE_ROUNDING ()
Packit Service a2489d
# define END_ROUNDING() END_LONG_DOUBLE_ROUNDING ()
Packit Service a2489d
# define L_(literal) literal##L
Packit Service a2489d
#else
Packit Service a2489d
# define FUNC printf_frexp
Packit Service a2489d
# define DOUBLE double
Packit Service a2489d
# define MIN_EXP DBL_MIN_EXP
Packit Service a2489d
# if HAVE_FREXP_IN_LIBC && HAVE_LDEXP_IN_LIBC
Packit Service a2489d
#  define USE_FREXP_LDEXP
Packit Service a2489d
#  define FREXP frexp
Packit Service a2489d
#  define LDEXP ldexp
Packit Service a2489d
# endif
Packit Service a2489d
# define DECL_ROUNDING
Packit Service a2489d
# define BEGIN_ROUNDING()
Packit Service a2489d
# define END_ROUNDING()
Packit Service a2489d
# define L_(literal) literal
Packit Service a2489d
#endif
Packit Service a2489d
Packit Service a2489d
DOUBLE
Packit Service a2489d
FUNC (DOUBLE x, int *expptr)
Packit Service a2489d
{
Packit Service a2489d
  int exponent;
Packit Service a2489d
  DECL_ROUNDING
Packit Service a2489d
Packit Service a2489d
  BEGIN_ROUNDING ();
Packit Service a2489d
Packit Service a2489d
#ifdef USE_FREXP_LDEXP
Packit Service a2489d
  /* frexp and ldexp are usually faster than the loop below.  */
Packit Service a2489d
  x = FREXP (x, &exponent);
Packit Service a2489d
Packit Service a2489d
  x = x + x;
Packit Service a2489d
  exponent -= 1;
Packit Service a2489d
Packit Service a2489d
  if (exponent < MIN_EXP - 1)
Packit Service a2489d
    {
Packit Service a2489d
      x = LDEXP (x, exponent - (MIN_EXP - 1));
Packit Service a2489d
      exponent = MIN_EXP - 1;
Packit Service a2489d
    }
Packit Service a2489d
#else
Packit Service a2489d
  {
Packit Service a2489d
    /* Since the exponent is an 'int', it fits in 64 bits.  Therefore the
Packit Service a2489d
       loops are executed no more than 64 times.  */
Packit Service a2489d
    DOUBLE pow2[64]; /* pow2[i] = 2^2^i */
Packit Service a2489d
    DOUBLE powh[64]; /* powh[i] = 2^-2^i */
Packit Service a2489d
    int i;
Packit Service a2489d
Packit Service a2489d
    exponent = 0;
Packit Service a2489d
    if (x >= L_(1.0))
Packit Service a2489d
      {
Packit Service a2489d
        /* A nonnegative exponent.  */
Packit Service a2489d
        {
Packit Service a2489d
          DOUBLE pow2_i; /* = pow2[i] */
Packit Service a2489d
          DOUBLE powh_i; /* = powh[i] */
Packit Service a2489d
Packit Service a2489d
          /* Invariants: pow2_i = 2^2^i, powh_i = 2^-2^i,
Packit Service a2489d
             x * 2^exponent = argument, x >= 1.0.  */
Packit Service a2489d
          for (i = 0, pow2_i = L_(2.0), powh_i = L_(0.5);
Packit Service a2489d
               ;
Packit Service a2489d
               i++, pow2_i = pow2_i * pow2_i, powh_i = powh_i * powh_i)
Packit Service a2489d
            {
Packit Service a2489d
              if (x >= pow2_i)
Packit Service a2489d
                {
Packit Service a2489d
                  exponent += (1 << i);
Packit Service a2489d
                  x *= powh_i;
Packit Service a2489d
                }
Packit Service a2489d
              else
Packit Service a2489d
                break;
Packit Service a2489d
Packit Service a2489d
              pow2[i] = pow2_i;
Packit Service a2489d
              powh[i] = powh_i;
Packit Service a2489d
            }
Packit Service a2489d
        }
Packit Service a2489d
        /* Here 1.0 <= x < 2^2^i.  */
Packit Service a2489d
      }
Packit Service a2489d
    else
Packit Service a2489d
      {
Packit Service a2489d
        /* A negative exponent.  */
Packit Service a2489d
        {
Packit Service a2489d
          DOUBLE pow2_i; /* = pow2[i] */
Packit Service a2489d
          DOUBLE powh_i; /* = powh[i] */
Packit Service a2489d
Packit Service a2489d
          /* Invariants: pow2_i = 2^2^i, powh_i = 2^-2^i,
Packit Service a2489d
             x * 2^exponent = argument, x < 1.0, exponent >= MIN_EXP - 1.  */
Packit Service a2489d
          for (i = 0, pow2_i = L_(2.0), powh_i = L_(0.5);
Packit Service a2489d
               ;
Packit Service a2489d
               i++, pow2_i = pow2_i * pow2_i, powh_i = powh_i * powh_i)
Packit Service a2489d
            {
Packit Service a2489d
              if (exponent - (1 << i) < MIN_EXP - 1)
Packit Service a2489d
                break;
Packit Service a2489d
Packit Service a2489d
              exponent -= (1 << i);
Packit Service a2489d
              x *= pow2_i;
Packit Service a2489d
              if (x >= L_(1.0))
Packit Service a2489d
                break;
Packit Service a2489d
Packit Service a2489d
              pow2[i] = pow2_i;
Packit Service a2489d
              powh[i] = powh_i;
Packit Service a2489d
            }
Packit Service a2489d
        }
Packit Service a2489d
        /* Here either x < 1.0 and exponent - 2^i < MIN_EXP - 1 <= exponent,
Packit Service a2489d
           or 1.0 <= x < 2^2^i and exponent >= MIN_EXP - 1.  */
Packit Service a2489d
Packit Service a2489d
        if (x < L_(1.0))
Packit Service a2489d
          /* Invariants: x * 2^exponent = argument, x < 1.0 and
Packit Service a2489d
             exponent - 2^i < MIN_EXP - 1 <= exponent.  */
Packit Service a2489d
          while (i > 0)
Packit Service a2489d
            {
Packit Service a2489d
              i--;
Packit Service a2489d
              if (exponent - (1 << i) >= MIN_EXP - 1)
Packit Service a2489d
                {
Packit Service a2489d
                  exponent -= (1 << i);
Packit Service a2489d
                  x *= pow2[i];
Packit Service a2489d
                  if (x >= L_(1.0))
Packit Service a2489d
                    break;
Packit Service a2489d
                }
Packit Service a2489d
            }
Packit Service a2489d
Packit Service a2489d
        /* Here either x < 1.0 and exponent = MIN_EXP - 1,
Packit Service a2489d
           or 1.0 <= x < 2^2^i and exponent >= MIN_EXP - 1.  */
Packit Service a2489d
      }
Packit Service a2489d
Packit Service a2489d
    /* Invariants: x * 2^exponent = argument, and
Packit Service a2489d
       either x < 1.0 and exponent = MIN_EXP - 1,
Packit Service a2489d
       or 1.0 <= x < 2^2^i and exponent >= MIN_EXP - 1.  */
Packit Service a2489d
    while (i > 0)
Packit Service a2489d
      {
Packit Service a2489d
        i--;
Packit Service a2489d
        if (x >= pow2[i])
Packit Service a2489d
          {
Packit Service a2489d
            exponent += (1 << i);
Packit Service a2489d
            x *= powh[i];
Packit Service a2489d
          }
Packit Service a2489d
      }
Packit Service a2489d
    /* Here either x < 1.0 and exponent = MIN_EXP - 1,
Packit Service a2489d
       or 1.0 <= x < 2.0 and exponent >= MIN_EXP - 1.  */
Packit Service a2489d
  }
Packit Service a2489d
#endif
Packit Service a2489d
Packit Service a2489d
  END_ROUNDING ();
Packit Service a2489d
Packit Service a2489d
  *expptr = exponent;
Packit Service a2489d
  return x;
Packit Service a2489d
}