Back to index

glibc  2.9
efgcvt_r.c
Go to the documentation of this file.
00001 /* Compatibility functions for floating point formatting, reentrant versions.
00002    Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2004, 2006
00003    Free Software Foundation, Inc.
00004    This file is part of the GNU C Library.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 #include <errno.h>
00022 #include <float.h>
00023 #include <stdio.h>
00024 #include <string.h>
00025 #include <ctype.h>
00026 #include <math.h>
00027 #include <stdlib.h>
00028 #include <sys/param.h>
00029 #include <math_ldbl_opt.h>
00030 
00031 #ifndef FLOAT_TYPE
00032 # define FLOAT_TYPE double
00033 # define FUNC_PREFIX
00034 # define FLOAT_FMT_FLAG
00035 # define FLOAT_NAME_EXT
00036 # define FLOAT_MIN_10_EXP DBL_MIN_10_EXP
00037 # if DBL_MANT_DIG == 53
00038 #  define NDIGIT_MAX 17
00039 # elif DBL_MANT_DIG == 24
00040 #  define NDIGIT_MAX 9
00041 # elif DBL_MANT_DIG == 56
00042 #  define NDIGIT_MAX 18
00043 # else
00044 /* See IEEE 854 5.6, table 2 for this formula.  Unfortunately we need a
00045    compile time constant here, so we cannot use it.  */
00046 #  error "NDIGIT_MAX must be precomputed"
00047 #  define NDIGIT_MAX (lrint (ceil (M_LN2 / M_LN10 * DBL_MANT_DIG + 1.0)))
00048 # endif
00049 # if DBL_MIN_10_EXP == -37
00050 #  define FLOAT_MIN_10_NORM 1.0e-37
00051 # elif DBL_MIN_10_EXP == -307
00052 #  define FLOAT_MIN_10_NORM 1.0e-307
00053 # elif DBL_MIN_10_EXP == -4931
00054 #  define FLOAT_MIN_10_NORM 1.0e-4931
00055 # else
00056 /* libc can't depend on libm.  */
00057 #  error "FLOAT_MIN_10_NORM must be precomputed"
00058 #  define FLOAT_MIN_10_NORM exp10 (DBL_MIN_10_EXP)
00059 # endif
00060 #else
00061 # define LONG_DOUBLE_CVT
00062 #endif
00063 
00064 #define APPEND(a, b) APPEND2 (a, b)
00065 #define APPEND2(a, b) a##b
00066 #define __APPEND(a, b) __APPEND2 (a, b)
00067 #define __APPEND2(a, b) __##a##b
00068 
00069 #define FLOOR APPEND(floor, FLOAT_NAME_EXT)
00070 #define FABS APPEND(fabs, FLOAT_NAME_EXT)
00071 #define LOG10 APPEND(log10, FLOAT_NAME_EXT)
00072 #define EXP APPEND(exp, FLOAT_NAME_EXT)
00073 
00074 
00075 int
00076 __APPEND (FUNC_PREFIX, fcvt_r) (value, ndigit, decpt, sign, buf, len)
00077      FLOAT_TYPE value;
00078      int ndigit, *decpt, *sign;
00079      char *buf;
00080      size_t len;
00081 {
00082   ssize_t n;
00083   ssize_t i;
00084   int left;
00085 
00086   if (buf == NULL)
00087     {
00088       __set_errno (EINVAL);
00089       return -1;
00090     }
00091 
00092   left = 0;
00093   if (isfinite (value))
00094     {
00095       *sign = signbit (value) != 0;
00096       if (*sign)
00097        value = -value;
00098 
00099       if (ndigit < 0)
00100        {
00101          /* Rounding to the left of the decimal point.  */
00102          while (ndigit < 0)
00103            {
00104              FLOAT_TYPE new_value = value * 0.1;
00105 
00106              if (new_value < 1.0)
00107               {
00108                 ndigit = 0;
00109                 break;
00110               }
00111 
00112              value = new_value;
00113              ++left;
00114              ++ndigit;
00115            }
00116        }
00117     }
00118   else
00119     /* Value is Inf or NaN.  */
00120     *sign = 0;
00121 
00122   n = __snprintf (buf, len, "%.*" FLOAT_FMT_FLAG "f", MIN (ndigit, NDIGIT_MAX),
00123                 value);
00124   /* Check for a too small buffer.  */
00125   if (n >= (ssize_t) len)
00126     return -1;
00127 
00128   i = 0;
00129   while (i < n && isdigit (buf[i]))
00130     ++i;
00131   *decpt = i;
00132 
00133   if (i == 0)
00134     /* Value is Inf or NaN.  */
00135     return 0;
00136 
00137   if (i < n)
00138     {
00139       do
00140        ++i;
00141       while (i < n && !isdigit (buf[i]));
00142 
00143       if (*decpt == 1 && buf[0] == '0' && value != 0.0)
00144        {
00145          /* We must not have leading zeroes.  Strip them all out and
00146             adjust *DECPT if necessary.  */
00147          --*decpt;
00148          while (i < n && buf[i] == '0')
00149            {
00150              --*decpt;
00151              ++i;
00152            }
00153        }
00154 
00155       memmove (&buf[MAX (*decpt, 0)], &buf[i], n - i);
00156       buf[n - (i - MAX (*decpt, 0))] = '\0';
00157     }
00158 
00159   if (left)
00160     {
00161       *decpt += left;
00162       if ((ssize_t) --len > n)
00163        {
00164          while (left-- > 0 && n < (ssize_t) len)
00165            buf[n++] = '0';
00166          buf[n] = '\0';
00167        }
00168     }
00169 
00170   return 0;
00171 }
00172 
00173 int
00174 __APPEND (FUNC_PREFIX, ecvt_r) (value, ndigit, decpt, sign, buf, len)
00175      FLOAT_TYPE value;
00176      int ndigit, *decpt, *sign;
00177      char *buf;
00178      size_t len;
00179 {
00180   int exponent = 0;
00181 
00182   if (isfinite (value) && value != 0.0)
00183     {
00184       /* Slow code that doesn't require -lm functions.  */
00185       FLOAT_TYPE d;
00186       FLOAT_TYPE f = 1.0;
00187       if (value < 0.0)
00188        d = -value;
00189       else
00190        d = value;
00191       /* For denormalized numbers the d < 1.0 case below won't work,
00192         as f can overflow to +Inf.  */
00193       if (d < FLOAT_MIN_10_NORM)
00194        {
00195          value /= FLOAT_MIN_10_NORM;
00196          if (value < 0.0)
00197            d = -value;
00198          else
00199            d = value;
00200          exponent += FLOAT_MIN_10_EXP;
00201        }
00202       if (d < 1.0)
00203        {
00204          do
00205            {
00206              f *= 10.0;
00207              --exponent;
00208            }
00209          while (d * f < 1.0);
00210 
00211          value *= f;
00212        }
00213       else if (d >= 10.0)
00214        {
00215          do
00216            {
00217              f *= 10;
00218              ++exponent;
00219            }
00220          while (d >= f * 10.0);
00221 
00222          value /= f;
00223        }
00224     }
00225   else if (value == 0.0)
00226     /* SUSv2 leaves it unspecified whether *DECPT is 0 or 1 for 0.0.
00227        This could be changed to -1 if we want to return 0.  */
00228     exponent = 0;
00229 
00230   if (ndigit <= 0 && len > 0)
00231     {
00232       buf[0] = '\0';
00233       *decpt = 1;
00234       *sign = isfinite (value) ? signbit (value) != 0 : 0;
00235     }
00236   else
00237     if (__APPEND (FUNC_PREFIX, fcvt_r) (value, MIN (ndigit, NDIGIT_MAX) - 1,
00238                                    decpt, sign, buf, len))
00239       return -1;
00240 
00241   *decpt += exponent;
00242   return 0;
00243 }
00244 
00245 #if LONG_DOUBLE_COMPAT (libc, GLIBC_2_0)
00246 # ifdef LONG_DOUBLE_CVT
00247 #  define cvt_symbol(symbol) \
00248   cvt_symbol_1 (libc, __APPEND (FUNC_PREFIX, symbol), \
00249              APPEND (FUNC_PREFIX, symbol), GLIBC_2_4)
00250 #  define cvt_symbol_1(lib, local, symbol, version) \
00251     versioned_symbol (lib, local, symbol, version)
00252 # else
00253 #  define cvt_symbol(symbol) \
00254   cvt_symbol_1 (libc, __APPEND (FUNC_PREFIX, symbol), \
00255              APPEND (q, symbol), GLIBC_2_0); \
00256   strong_alias (__APPEND (FUNC_PREFIX, symbol), APPEND (FUNC_PREFIX, symbol))
00257 #  define cvt_symbol_1(lib, local, symbol, version) \
00258   compat_symbol (lib, local, symbol, version)
00259 # endif
00260 #else
00261 # define cvt_symbol(symbol) \
00262   strong_alias (__APPEND (FUNC_PREFIX, symbol), APPEND (FUNC_PREFIX, symbol))
00263 #endif
00264 cvt_symbol(fcvt_r);
00265 cvt_symbol(ecvt_r);