Annotation of OpenXM_contrib/gmp/printf/doprntf.c, Revision 1.1
1.1 ! ohara 1: /* __gmp_doprnt_mpf -- mpf formatted output.
! 2:
! 3: THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY. THEY'RE ALMOST
! 4: CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
! 5: FUTURE GNU MP RELEASES.
! 6:
! 7: Copyright 2001, 2002 Free Software Foundation, Inc.
! 8:
! 9: This file is part of the GNU MP Library.
! 10:
! 11: The GNU MP Library is free software; you can redistribute it and/or modify
! 12: it under the terms of the GNU Lesser General Public License as published by
! 13: the Free Software Foundation; either version 2.1 of the License, or (at your
! 14: option) any later version.
! 15:
! 16: The GNU MP Library is distributed in the hope that it will be useful, but
! 17: WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 18: or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
! 19: License for more details.
! 20:
! 21: You should have received a copy of the GNU Lesser General Public License
! 22: along with the GNU MP Library; see the file COPYING.LIB. If not, write to
! 23: the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
! 24: MA 02111-1307, USA. */
! 25:
! 26: #include "config.h"
! 27:
! 28: #if HAVE_STDARG
! 29: #include <stdarg.h> /* for va_list and hence doprnt_funs_t */
! 30: #else
! 31: #include <varargs.h>
! 32: #endif
! 33:
! 34: #include <ctype.h>
! 35: #include <string.h>
! 36: #include <stdio.h>
! 37: #include <stdlib.h>
! 38:
! 39: #if HAVE_LOCALE_H
! 40: #include <locale.h> /* for localeconv */
! 41: #endif
! 42:
! 43: #include "gmp.h"
! 44: #include "gmp-impl.h"
! 45:
! 46:
! 47: /* change this to "#define TRACE(x) x" for diagnostics */
! 48: #define TRACE(x)
! 49:
! 50:
! 51: /* The separate of __gmp_doprnt_float_digits and __gmp_doprnt_float is so
! 52: some C++ can do the mpf_get_str and release it in case of an exception */
! 53:
! 54: #define DIGIT_VALUE(c) \
! 55: (isdigit (c) ? (c) - '0' \
! 56: : islower (c) ? (c) - 'a' + 10 \
! 57: : (c) - 'A' + 10)
! 58:
! 59: int
! 60: __gmp_doprnt_mpf (const struct doprnt_funs_t *funs,
! 61: void *data,
! 62: const struct doprnt_params_t *p,
! 63: mpf_srcptr f)
! 64: {
! 65: int prec, ndigits, free_size, len, newlen, justify, justlen, explen;
! 66: int showbaselen, sign, signlen, intlen, intzeros, pointlen;
! 67: int fraczeros, fraclen, preczeros;
! 68: char *s, *free_ptr;
! 69: mp_exp_t exp;
! 70: char exponent[BITS_PER_MP_LIMB + 10];
! 71: const char *showbase;
! 72: const char *point;
! 73: int retval = 0;
! 74:
! 75: TRACE (printf ("__gmp_doprnt_float\n");
! 76: printf (" conv=%d prec=%d\n", p->conv, p->prec));
! 77:
! 78: prec = p->prec;
! 79: if (prec <= -1)
! 80: {
! 81: /* all digits */
! 82: ndigits = 0;
! 83:
! 84: /* arrange the fixed/scientific decision on a "prec" implied by how
! 85: many significant digits there are */
! 86: if (p->conv == DOPRNT_CONV_GENERAL)
! 87: MPF_SIGNIFICANT_DIGITS (prec, PREC(f), ABS(p->base));
! 88: }
! 89: else
! 90: {
! 91: switch (p->conv) {
! 92: case DOPRNT_CONV_FIXED:
! 93: /* Precision is digits after the radix point. Try not to generate
! 94: too many more than will actually be required. If f>=1 then
! 95: overestimate the integer part, and add prec. If f<1 then
! 96: underestimate the zeros between the radix point and the first
! 97: digit and subtract that from prec. In either case add 2 so the
! 98: round to nearest can be applied accurately. */
! 99: ndigits = prec + 2
! 100: + EXP(f) * (__mp_bases[ABS(p->base)].chars_per_limb + (EXP(f)>=0));
! 101: ndigits = MAX (ndigits, 1);
! 102: break;
! 103:
! 104: case DOPRNT_CONV_SCIENTIFIC:
! 105: /* precision is digits after the radix point, and there's one digit
! 106: before */
! 107: ndigits = prec + 1;
! 108: break;
! 109:
! 110: default:
! 111: ASSERT (0);
! 112: /*FALLTHRU*/
! 113:
! 114: case DOPRNT_CONV_GENERAL:
! 115: /* precision is total digits, but be sure to ask mpf_get_str for at
! 116: least 1, not 0 */
! 117: ndigits = MAX (prec, 1);
! 118: break;
! 119: }
! 120: }
! 121: TRACE (printf (" ndigits %d\n", ndigits));
! 122:
! 123: s = mpf_get_str (NULL, &exp, p->base, ndigits, f);
! 124: len = strlen (s);
! 125: free_ptr = s;
! 126: free_size = len + 1;
! 127: TRACE (printf (" s %s\n", s);
! 128: printf (" exp %ld\n", exp);
! 129: printf (" len %d\n", len));
! 130:
! 131: /* For fixed mode check the ndigits formed above was in fact enough for
! 132: the integer part plus p->prec after the radix point. */
! 133: ASSERT ((p->conv == DOPRNT_CONV_FIXED && p->prec > -1)
! 134: ? ndigits >= MAX (1, exp + p->prec + 2) : 1);
! 135:
! 136: sign = p->sign;
! 137: if (s[0] == '-')
! 138: {
! 139: sign = s[0];
! 140: s++, len--;
! 141: }
! 142: signlen = (sign != '\0');
! 143: TRACE (printf (" sign %c signlen %d\n", sign, signlen));
! 144:
! 145: switch (p->conv) {
! 146: case DOPRNT_CONV_FIXED:
! 147: if (prec <= -1)
! 148: prec = MAX (0, len-exp); /* retain all digits */
! 149:
! 150: /* Truncate if necessary so fraction will be at most prec digits. */
! 151: ASSERT (prec >= 0);
! 152: newlen = exp + prec;
! 153: if (newlen < 0)
! 154: {
! 155: /* first non-zero digit is below target prec, and at least one zero
! 156: digit in between, so print zero */
! 157: len = 0;
! 158: exp = 0;
! 159: }
! 160: else if (len <= newlen)
! 161: {
! 162: /* already got few enough digits */
! 163: }
! 164: else
! 165: {
! 166: /* discard excess digits and round to nearest */
! 167:
! 168: const char *num_to_text = (p->base >= 0
! 169: ? "0123456789abcdefghijklmnopqrstuvwxyz"
! 170: : "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ");
! 171: int base = ABS(p->base);
! 172: int n;
! 173:
! 174: ASSERT (base <= 36);
! 175:
! 176: len = newlen;
! 177: n = DIGIT_VALUE (s[len]);
! 178: TRACE (printf (" rounding with %d\n", n));
! 179: if (n >= (base + 1) / 2)
! 180: {
! 181: /* propagate a carry */
! 182: for (;;)
! 183: {
! 184: if (len == 0)
! 185: {
! 186: s[0] = '1';
! 187: len = 1;
! 188: exp++;
! 189: break;
! 190: }
! 191: n = DIGIT_VALUE (s[len-1]);
! 192: ASSERT (n >= 0 && n < base);
! 193: n++;
! 194: if (n != base)
! 195: {
! 196: TRACE (printf (" storing now %d\n", n));
! 197: s[len-1] = num_to_text[n];
! 198: break;
! 199: }
! 200: len--;
! 201: }
! 202: }
! 203: else
! 204: {
! 205: /* truncate only, strip any trailing zeros now exposed */
! 206: while (len > 0 && s[len-1] == '0')
! 207: len--;
! 208: }
! 209:
! 210: /* Can have newlen==0, in which case the truncate was just to check
! 211: for a carry turning it into "1". If we're left with len==0 then
! 212: adjust exp to match. */
! 213: if (len == 0)
! 214: exp = 0;
! 215: }
! 216:
! 217: fixed:
! 218: ASSERT (len == 0 ? exp == 0 : 1);
! 219: if (exp <= 0)
! 220: {
! 221: TRACE (printf (" fixed 0.000sss\n"));
! 222: intlen = 0;
! 223: intzeros = 1;
! 224: fraczeros = -exp;
! 225: fraclen = len;
! 226: }
! 227: else
! 228: {
! 229: TRACE (printf (" fixed sss.sss or sss000\n"));
! 230: intlen = MIN (len, exp);
! 231: intzeros = exp - intlen;
! 232: fraczeros = 0;
! 233: fraclen = len - intlen;
! 234: }
! 235: explen = 0;
! 236: break;
! 237:
! 238: case DOPRNT_CONV_SCIENTIFIC:
! 239: {
! 240: int expval;
! 241: char expsign;
! 242:
! 243: if (prec <= -1)
! 244: prec = MAX (0, len-1); /* retain all digits */
! 245:
! 246: scientific:
! 247: TRACE (printf (" scientific s.sss\n"));
! 248:
! 249: intlen = MIN (1, len);
! 250: intzeros = (intlen == 0 ? 1 : 0);
! 251: fraczeros = 0;
! 252: fraclen = len - intlen;
! 253:
! 254: expval = (exp-intlen);
! 255: if (p->exptimes4)
! 256: expval <<= 2;
! 257:
! 258: /* Split out the sign since %o or %x in expfmt give negatives as twos
! 259: complement, not with a sign. */
! 260: expsign = (expval >= 0 ? '+' : '-');
! 261: expval = ABS (expval);
! 262:
! 263: #if HAVE_VSNPRINTF
! 264: explen = snprintf (exponent, sizeof(exponent),
! 265: p->expfmt, expsign, expval);
! 266: /* test for < sizeof-1 since a glibc 2.0.x return of sizeof-1 might
! 267: mean truncation */
! 268: ASSERT (explen >= 0 && explen < sizeof(exponent)-1);
! 269: #else
! 270: sprintf (exponent, p->expfmt, expsign, expval);
! 271: explen = strlen (exponent);
! 272: ASSERT (explen < sizeof(exponent));
! 273: #endif
! 274: TRACE (printf (" expfmt %s gives %s\n", p->expfmt, exponent));
! 275: }
! 276: break;
! 277:
! 278: default:
! 279: ASSERT (0);
! 280: /*FALLTHRU*/ /* to stop variables looking uninitialized */
! 281:
! 282: case DOPRNT_CONV_GENERAL:
! 283: /* The exponent for "scientific" will be exp-1, choose scientific if
! 284: this is < -4 or >= prec (and minimum 1 for prec). For f==0 will have
! 285: exp==0 and get the desired "fixed". This rule follows glibc. For
! 286: fixed there's no need to truncate, the desired ndigits will already
! 287: be as required. */
! 288: if (exp-1 < -4 || exp-1 >= MAX (1, prec))
! 289: goto scientific;
! 290: else
! 291: goto fixed;
! 292: }
! 293:
! 294: TRACE (printf (" intlen %d intzeros %d fraczeros %d fraclen %d\n",
! 295: intlen, intzeros, fraczeros, fraclen));
! 296: ASSERT (p->prec <= -1
! 297: ? intlen + fraclen == strlen (s)
! 298: : intlen + fraclen <= strlen (s));
! 299:
! 300: if (p->showtrailing)
! 301: {
! 302: /* Pad to requested precision with trailing zeros, for general this is
! 303: all digits, for fixed and scientific just the fraction. */
! 304: preczeros = prec - (fraczeros + fraclen
! 305: + (p->conv == DOPRNT_CONV_GENERAL
! 306: ? intlen + intzeros : 0));
! 307: preczeros = MAX (0, preczeros);
! 308: }
! 309: else
! 310: preczeros = 0;
! 311: TRACE (printf (" prec=%d showtrailing=%d, pad with preczeros %d\n",
! 312: prec, p->showtrailing, preczeros));
! 313:
! 314: /* radix point if needed, or if forced */
! 315: point = ".";
! 316: pointlen = ((fraczeros + fraclen + preczeros) != 0 || p->showpoint != 0);
! 317: #if HAVE_LOCALECONV
! 318: if (pointlen)
! 319: {
! 320: point = localeconv()->decimal_point;
! 321: pointlen = strlen (point);
! 322: }
! 323: #endif
! 324: TRACE (printf (" point |%s| pointlen %d\n", point, pointlen));
! 325:
! 326: /* Notice the test for a non-zero value is done after any truncation for
! 327: DOPRNT_CONV_FIXED. */
! 328: showbase = NULL;
! 329: showbaselen = 0;
! 330: switch (p->showbase) {
! 331: default:
! 332: ASSERT (0);
! 333: /*FALLTHRU*/
! 334: case DOPRNT_SHOWBASE_NO:
! 335: break;
! 336: case DOPRNT_SHOWBASE_NONZERO:
! 337: if (intlen == 0 && fraclen == 0)
! 338: break;
! 339: /*FALLTHRU*/
! 340: case DOPRNT_SHOWBASE_YES:
! 341: switch (p->base) {
! 342: case 16: showbase = "0x"; showbaselen = 2; break;
! 343: case -16: showbase = "0X"; showbaselen = 2; break;
! 344: case 8: showbase = "0"; showbaselen = 1; break;
! 345: }
! 346: break;
! 347: }
! 348: TRACE (printf (" showbase %s showbaselen %d\n",
! 349: showbase == NULL ? "" : showbase, showbaselen));
! 350:
! 351: /* left over field width */
! 352: justlen = p->width - (signlen + showbaselen + intlen + intzeros + pointlen
! 353: + fraczeros + fraclen + preczeros + explen);
! 354: TRACE (printf (" justlen %d fill 0x%X\n", justlen, p->fill));
! 355:
! 356: justify = p->justify;
! 357: if (justlen <= 0) /* no justifying if exceed width */
! 358: justify = DOPRNT_JUSTIFY_NONE;
! 359:
! 360: TRACE (printf (" justify type %d intlen %d pointlen %d fraclen %d\n",
! 361: justify, intlen, pointlen, fraclen));
! 362:
! 363: if (justify == DOPRNT_JUSTIFY_RIGHT) /* pad for right */
! 364: DOPRNT_REPS (p->fill, justlen);
! 365:
! 366: if (signlen) /* sign */
! 367: DOPRNT_REPS (sign, 1);
! 368:
! 369: DOPRNT_MEMORY_MAYBE (showbase, showbaselen); /* base */
! 370:
! 371: if (justify == DOPRNT_JUSTIFY_INTERNAL) /* pad for internal */
! 372: DOPRNT_REPS (p->fill, justlen);
! 373:
! 374: DOPRNT_MEMORY (s, intlen); /* integer */
! 375: DOPRNT_REPS_MAYBE ('0', intzeros);
! 376:
! 377: DOPRNT_MEMORY_MAYBE (point, pointlen); /* point */
! 378:
! 379: DOPRNT_REPS_MAYBE ('0', fraczeros); /* frac */
! 380: DOPRNT_MEMORY_MAYBE (s+intlen, fraclen);
! 381:
! 382: DOPRNT_REPS_MAYBE ('0', preczeros); /* prec */
! 383:
! 384: DOPRNT_MEMORY_MAYBE (exponent, explen); /* exp */
! 385:
! 386: if (justify == DOPRNT_JUSTIFY_LEFT) /* pad for left */
! 387: DOPRNT_REPS (p->fill, justlen);
! 388:
! 389: done:
! 390: (*__gmp_free_func) (free_ptr, free_size);
! 391: return retval;
! 392:
! 393: error:
! 394: retval = -1;
! 395: goto done;
! 396: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>