OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libquadmath/] [printf/] [printf_fphex.c] - Blame information for rev 740

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 740 jeremybenn
/* Print floating point number in hexadecimal notation according to ISO C99.
2
   Copyright (C) 1997-2002,2004,2006 Free Software Foundation, Inc.
3
   This file is part of the GNU C Library.
4
   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
5
 
6
   The GNU C Library is free software; you can redistribute it and/or
7
   modify it under the terms of the GNU Lesser General Public
8
   License as published by the Free Software Foundation; either
9
   version 2.1 of the License, or (at your option) any later version.
10
 
11
   The GNU C Library is distributed in the hope that it will be useful,
12
   but WITHOUT ANY WARRANTY; without even the implied warranty of
13
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
   Lesser General Public License for more details.
15
 
16
   You should have received a copy of the GNU Lesser General Public
17
   License along with the GNU C Library; if not, write to the Free
18
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19
   02111-1307 USA.  */
20
 
21
#include <config.h>
22
#include <math.h>
23
#include <stdlib.h>
24
#include <stdio.h>
25
#include <string.h>
26
#define NDEBUG
27
#include <assert.h>
28
#include "quadmath-printf.h"
29
#include "_itoa.h"
30
#include "_itowa.h"
31
 
32
 
33
/* Macros for doing the actual output.  */
34
 
35
#define outchar(ch)                                                           \
36
  do                                                                          \
37
    {                                                                         \
38
      register const int outc = (ch);                                         \
39
      if (PUTC (outc, fp) == EOF)                                             \
40
        return -1;                                                            \
41
      ++done;                                                                 \
42
    } while (0)
43
 
44
#define PRINT(ptr, wptr, len)                                                 \
45
  do                                                                          \
46
    {                                                                         \
47
      register size_t outlen = (len);                                         \
48
      if (wide)                                                               \
49
        while (outlen-- > 0)                                                   \
50
          outchar (*wptr++);                                                  \
51
      else                                                                    \
52
        while (outlen-- > 0)                                                   \
53
          outchar (*ptr++);                                                   \
54
    } while (0)
55
 
56
#define PADN(ch, len)                                                         \
57
  do                                                                          \
58
    {                                                                         \
59
      if (PAD (fp, ch, len) != len)                                           \
60
        return -1;                                                            \
61
      done += len;                                                            \
62
    }                                                                         \
63
  while (0)
64
 
65
 
66
 
67
int
68
__quadmath_printf_fphex (struct __quadmath_printf_file *fp,
69
                         const struct printf_info *info,
70
                         const void *const *args)
71
{
72
  /* The floating-point value to output.  */
73
  ieee854_float128 fpnum;
74
 
75
  /* Locale-dependent representation of decimal point.  */
76
  const char *decimal;
77
  wchar_t decimalwc;
78
 
79
  /* "NaN" or "Inf" for the special cases.  */
80
  const char *special = NULL;
81
  const wchar_t *wspecial = NULL;
82
 
83
  /* Buffer for the generated number string for the mantissa.  The
84
     maximal size for the mantissa is 128 bits.  */
85
  char numbuf[32];
86
  char *numstr;
87
  char *numend;
88
  wchar_t wnumbuf[32];
89
  wchar_t *wnumstr;
90
  wchar_t *wnumend;
91
  int negative;
92
 
93
  /* The maximal exponent of two in decimal notation has 5 digits.  */
94
  char expbuf[5];
95
  char *expstr;
96
  wchar_t wexpbuf[5];
97
  wchar_t *wexpstr;
98
  int expnegative;
99
  int exponent;
100
 
101
  /* Non-zero is mantissa is zero.  */
102
  int zero_mantissa;
103
 
104
  /* The leading digit before the decimal point.  */
105
  char leading;
106
 
107
  /* Precision.  */
108
  int precision = info->prec;
109
 
110
  /* Width.  */
111
  int width = info->width;
112
 
113
  /* Number of characters written.  */
114
  int done = 0;
115
 
116
  /* Nonzero if this is output on a wide character stream.  */
117
  int wide = info->wide;
118
 
119
  /* Figure out the decimal point character.  */
120
#ifdef USE_NL_LANGINFO
121
  if (info->extra == 0)
122
    decimal = nl_langinfo (DECIMAL_POINT);
123
  else
124
    {
125
      decimal = nl_langinfo (MON_DECIMAL_POINT);
126
      if (*decimal == '\0')
127
        decimal = nl_langinfo (DECIMAL_POINT);
128
    }
129
  /* The decimal point character must never be zero.  */
130
  assert (*decimal != '\0');
131
#elif defined USE_LOCALECONV
132
  const struct lconv *lc = localeconv ();
133
  if (info->extra == 0)
134
    decimal = lc->decimal_point;
135
  else
136
    {
137
      decimal = lc->mon_decimal_point;
138
      if (decimal == NULL || *decimal == '\0')
139
        decimal = lc->decimal_point;
140
    }
141
  if (decimal == NULL || *decimal == '\0')
142
    decimal = ".";
143
#else
144
  decimal = ".";
145
#endif
146
#ifdef USE_NL_LANGINFO_WC
147
  if (info->extra == 0)
148
    decimalwc = nl_langinfo_wc (_NL_NUMERIC_DECIMAL_POINT_WC);
149
  else
150
    {
151
      decimalwc = nl_langinfo_wc (_NL_MONETARY_DECIMAL_POINT_WC);
152
      if (decimalwc == L_('\0'))
153
        decimalwc = nl_langinfo_wc (_NL_NUMERIC_DECIMAL_POINT_WC);
154
    }
155
  /* The decimal point character must never be zero.  */
156
  assert (decimalwc != L_('\0'));
157
#else
158
  decimalwc = L_('.');
159
#endif
160
 
161
  /* Fetch the argument value.  */
162
    {
163
      fpnum.value = **(const __float128 **) args[0];
164
 
165
      /* Check for special values: not a number or infinity.  */
166
      if (isnanq (fpnum.value))
167
        {
168
          negative = fpnum.ieee.negative != 0;
169
          if (isupper (info->spec))
170
            {
171
              special = "NAN";
172
              wspecial = L_("NAN");
173
            }
174
          else
175
            {
176
              special = "nan";
177
              wspecial = L_("nan");
178
            }
179
        }
180
      else
181
        {
182
          if (isinfq (fpnum.value))
183
            {
184
              if (isupper (info->spec))
185
                {
186
                  special = "INF";
187
                  wspecial = L_("INF");
188
                }
189
              else
190
                {
191
                  special = "inf";
192
                  wspecial = L_("inf");
193
                }
194
            }
195
 
196
          negative = signbitq (fpnum.value);
197
        }
198
    }
199
 
200
  if (special)
201
    {
202
      int width = info->width;
203
 
204
      if (negative || info->showsign || info->space)
205
        --width;
206
      width -= 3;
207
 
208
      if (!info->left && width > 0)
209
        PADN (' ', width);
210
 
211
      if (negative)
212
        outchar ('-');
213
      else if (info->showsign)
214
        outchar ('+');
215
      else if (info->space)
216
        outchar (' ');
217
 
218
      PRINT (special, wspecial, 3);
219
 
220
      if (info->left && width > 0)
221
        PADN (' ', width);
222
 
223
      return done;
224
    }
225
 
226
    {
227
      /* We have 112 bits of mantissa plus one implicit digit.  Since
228
         112 bits are representable without rest using hexadecimal
229
         digits we use only the implicit digits for the number before
230
         the decimal point.  */
231
      uint64_t num0, num1;
232
 
233
      assert (sizeof (long double) == 16);
234
 
235
      num0 = fpnum.ieee.mant_high;
236
      num1 = fpnum.ieee.mant_low;
237
 
238
      zero_mantissa = (num0|num1) == 0;
239
 
240
      if (sizeof (unsigned long int) > 6)
241
        {
242
          numstr = _itoa_word (num1, numbuf + sizeof numbuf, 16,
243
                               info->spec == 'A');
244
          wnumstr = _itowa_word (num1,
245
                                 wnumbuf + sizeof (wnumbuf) / sizeof (wchar_t),
246
                                 16, info->spec == 'A');
247
        }
248
      else
249
        {
250
          numstr = _itoa (num1, numbuf + sizeof numbuf, 16,
251
                          info->spec == 'A');
252
          wnumstr = _itowa (num1,
253
                            wnumbuf + sizeof (wnumbuf) / sizeof (wchar_t),
254
                            16, info->spec == 'A');
255
        }
256
 
257
      while (numstr > numbuf + (sizeof numbuf - 64 / 4))
258
        {
259
          *--numstr = '0';
260
          *--wnumstr = L_('0');
261
        }
262
 
263
      if (sizeof (unsigned long int) > 6)
264
        {
265
          numstr = _itoa_word (num0, numstr, 16, info->spec == 'A');
266
          wnumstr = _itowa_word (num0, wnumstr, 16, info->spec == 'A');
267
        }
268
      else
269
        {
270
          numstr = _itoa (num0, numstr, 16, info->spec == 'A');
271
          wnumstr = _itowa (num0, wnumstr, 16, info->spec == 'A');
272
        }
273
 
274
      /* Fill with zeroes.  */
275
      while (numstr > numbuf + (sizeof numbuf - 112 / 4))
276
        {
277
          *--numstr = '0';
278
          *--wnumstr = L_('0');
279
        }
280
 
281
      leading = fpnum.ieee.exponent == 0 ? '0' : '1';
282
 
283
      exponent = fpnum.ieee.exponent;
284
 
285
      if (exponent == 0)
286
        {
287
          if (zero_mantissa)
288
            expnegative = 0;
289
          else
290
            {
291
              /* This is a denormalized number.  */
292
              expnegative = 1;
293
              exponent = IEEE854_FLOAT128_BIAS - 1;
294
            }
295
        }
296
      else if (exponent >= IEEE854_FLOAT128_BIAS)
297
        {
298
          expnegative = 0;
299
          exponent -= IEEE854_FLOAT128_BIAS;
300
        }
301
      else
302
        {
303
          expnegative = 1;
304
          exponent = -(exponent - IEEE854_FLOAT128_BIAS);
305
        }
306
    }
307
 
308
  /* Look for trailing zeroes.  */
309
  if (! zero_mantissa)
310
    {
311
      wnumend = &wnumbuf[sizeof wnumbuf / sizeof wnumbuf[0]];
312
      numend = &numbuf[sizeof numbuf / sizeof numbuf[0]];
313
      while (wnumend[-1] == L_('0'))
314
        {
315
          --wnumend;
316
          --numend;
317
        }
318
 
319
      if (precision == -1)
320
        precision = numend - numstr;
321
      else if (precision < numend - numstr
322
               && (numstr[precision] > '8'
323
                   || (('A' < '0' || 'a' < '0')
324
                       && numstr[precision] < '0')
325
                   || (numstr[precision] == '8'
326
                       && (precision + 1 < numend - numstr
327
                           /* Round to even.  */
328
                           || (precision > 0
329
                               && ((numstr[precision - 1] & 1)
330
                                   ^ (isdigit (numstr[precision - 1]) == 0)))
331
                           || (precision == 0
332
                               && ((leading & 1)
333
                                   ^ (isdigit (leading) == 0)))))))
334
        {
335
          /* Round up.  */
336
          int cnt = precision;
337
          while (--cnt >= 0)
338
            {
339
              char ch = numstr[cnt];
340
              /* We assume that the digits and the letters are ordered
341
                 like in ASCII.  This is true for the rest of GNU, too.  */
342
              if (ch == '9')
343
                {
344
                  wnumstr[cnt] = (wchar_t) info->spec;
345
                  numstr[cnt] = info->spec;     /* This is tricky,
346
                                                   think about it!  */
347
                  break;
348
                }
349
              else if (tolower (ch) < 'f')
350
                {
351
                  ++numstr[cnt];
352
                  ++wnumstr[cnt];
353
                  break;
354
                }
355
              else
356
                {
357
                  numstr[cnt] = '0';
358
                  wnumstr[cnt] = L_('0');
359
                }
360
            }
361
          if (cnt < 0)
362
            {
363
              /* The mantissa so far was fff...f  Now increment the
364
                 leading digit.  Here it is again possible that we
365
                 get an overflow.  */
366
              if (leading == '9')
367
                leading = info->spec;
368
              else if (tolower (leading) < 'f')
369
                ++leading;
370
              else
371
                {
372
                  leading = '1';
373
                  if (expnegative)
374
                    {
375
                      exponent -= 4;
376
                      if (exponent <= 0)
377
                        {
378
                          exponent = -exponent;
379
                          expnegative = 0;
380
                        }
381
                    }
382
                  else
383
                    exponent += 4;
384
                }
385
            }
386
        }
387
    }
388
  else
389
    {
390
      if (precision == -1)
391
        precision = 0;
392
      numend = numstr;
393
      wnumend = wnumstr;
394
    }
395
 
396
  /* Now we can compute the exponent string.  */
397
  expstr = _itoa_word (exponent, expbuf + sizeof expbuf, 10, 0);
398
  wexpstr = _itowa_word (exponent,
399
                         wexpbuf + sizeof wexpbuf / sizeof (wchar_t), 10, 0);
400
 
401
  /* Now we have all information to compute the size.  */
402
  width -= ((negative || info->showsign || info->space)
403
            /* Sign.  */
404
            + 2    + 1 + 0 + precision + 1 + 1
405
            /* 0x    h   .   hhh         P   ExpoSign.  */
406
            + ((expbuf + sizeof expbuf) - expstr));
407
            /* Exponent.  */
408
 
409
  /* Count the decimal point.
410
     A special case when the mantissa or the precision is zero and the `#'
411
     is not given.  In this case we must not print the decimal point.  */
412
  if (precision > 0 || info->alt)
413
    width -= wide ? 1 : strlen (decimal);
414
 
415
  if (!info->left && info->pad != '0' && width > 0)
416
    PADN (' ', width);
417
 
418
  if (negative)
419
    outchar ('-');
420
  else if (info->showsign)
421
    outchar ('+');
422
  else if (info->space)
423
    outchar (' ');
424
 
425
  outchar ('0');
426
  if ('X' - 'A' == 'x' - 'a')
427
    outchar (info->spec + ('x' - 'a'));
428
  else
429
    outchar (info->spec == 'A' ? 'X' : 'x');
430
 
431
  if (!info->left && info->pad == '0' && width > 0)
432
    PADN ('0', width);
433
 
434
  outchar (leading);
435
 
436
  if (precision > 0 || info->alt)
437
    {
438
      const wchar_t *wtmp = &decimalwc;
439
      PRINT (decimal, wtmp, wide ? 1 : strlen (decimal));
440
    }
441
 
442
  if (precision > 0)
443
    {
444
      ssize_t tofill = precision - (numend - numstr);
445
      PRINT (numstr, wnumstr, MIN (numend - numstr, precision));
446
      if (tofill > 0)
447
        PADN ('0', tofill);
448
    }
449
 
450
  if ('P' - 'A' == 'p' - 'a')
451
    outchar (info->spec + ('p' - 'a'));
452
  else
453
    outchar (info->spec == 'A' ? 'P' : 'p');
454
 
455
  outchar (expnegative ? '-' : '+');
456
 
457
  PRINT (expstr, wexpstr, (expbuf + sizeof expbuf) - expstr);
458
 
459
  if (info->left && info->pad != '0' && width > 0)
460
    PADN (info->pad, width);
461
 
462
  return done;
463
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.