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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [newlib/] [newlib/] [libm/] [test/] [dcvt.c] - Blame information for rev 39

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 39 lampret
 
2
 
3
#include <limits.h>
4
#include <math.h>
5
#include <stdio.h>
6
#include <float.h>
7
#include <ieeefp.h>
8
#include <stdlib.h>
9
#include <string.h>
10
#define _MAX_CHARS 512
11
 
12
static char *lcset = "0123456789abcdef";
13
 
14
static struct p {
15
        double pvalue, nvalue;
16
        int exp;
17
} powers[] =
18
{
19
{ 1e32, 1e-32, 32},
20
{ 1e16, 1e-16, 16},
21
{ 1e8, 1e-8, 8},
22
{ 1e4, 1e-4, 4},
23
{ 1e2, 1e-2, 2},
24
{ 1e1, 1e-1, 1 },
25
{ 1e0, 1e-0, 0 }
26
};
27
 
28
#define _MAX_PREC 16
29
 
30
static char
31
_DEFUN(nextdigit,(value),
32
double *value)
33
{
34
  double tmp;
35
 
36
  *value = modf (*value * 10, &tmp) ;
37
  return  lcset[(int)tmp];
38
}
39
 
40
 
41
static char *
42
_DEFUN(print_nan,(buffer, value, precision),
43
       char *buffer _AND
44
       double value _AND
45
       int precision)
46
{
47
  size_t  i;
48
 
49
  if (isnan(value))
50
    {
51
      strcpy(buffer, "nan");
52
      i = 3;
53
 
54
    }
55
  else
56
    {
57
      strcpy(buffer, "infinity");
58
      i = 8;
59
    }
60
 
61
  while (i < precision)
62
    {
63
      buffer[i++] = ' ';
64
    }
65
  buffer[i++] = 0;
66
  return buffer;
67
 
68
}
69
 
70
/* A convert info struct */
71
typedef struct
72
{
73
  char *buffer ;                /* Destination of conversion */
74
  double value;                 /* scratch Value to convert */
75
  double original_value;        /* saved Value to convert */
76
  int value_neg;                /* OUT: 1 if value initialiy neg */
77
  int abs_exp;                  /* abs Decimal exponent of value */
78
  int abs_exp_sign;             /* + or - */
79
  int exp;                      /* exp not sgned */
80
  int type;                     /* fFeEgG used in printing before exp */
81
 
82
  int print_trailing_zeros;     /* Print 00's after a . */
83
 
84
  int null_idx;  /* Index of the null at the end */
85
 
86
/* These ones are read only */
87
  int decimal_places;           /* the number of digits to print after
88
                                   the decimal */
89
  int max_digits;               /* total number of digits to print */
90
  int buffer_size;              /* Size of output buffer */
91
 
92
  /* Two sorts of dot ness.
93
 
94
     1  print a dot if followed by a digit
95
     2  always print a dot, even if no digit following
96
     */
97
  enum { dot_never, dot_sometimes, dot_always} dot; /* Print a decimal point, always */
98
  int dot_idx;                  /* where the dot went, or would have gone */
99
} cvt_info_type;
100
 
101
 
102
void
103
_DEFUN(renormalize,(in),
104
       cvt_info_type *in)
105
{
106
 
107
  /* Make sure all numbers are less than 1 */
108
 
109
  while (in->value >= 1.0)
110
  {
111
    in->value = in->value * 0.1;
112
    in->exp++;
113
  }
114
 
115
  /* Now we have only numbers between 0 and .9999.., and have adjusted
116
     exp to account for the shift */
117
 
118
  if (in->exp >= 0)
119
  {
120
    in->abs_exp_sign = '+';
121
    in->abs_exp = in->exp;
122
  }
123
  else
124
  {
125
    in->abs_exp_sign  = '-';
126
    in->abs_exp = -in->exp;
127
  }
128
 
129
}
130
 
131
/* This routine looks at original_value, and makes it between 0 and 1,
132
   modifying exp as it goes
133
 */
134
 
135
static void
136
_DEFUN(normalize,(value, in),
137
       double value _AND
138
       cvt_info_type *in)
139
{
140
  int j;
141
  int texp;
142
  if (value != 0)
143
  {
144
     texp = -1;
145
 
146
 
147
  if (value < 0.0)
148
  {
149
    in->value_neg =1 ;
150
    value = - value;
151
  }
152
  else
153
  {
154
    in->value_neg = 0;
155
  }
156
 
157
 
158
  /* Work out texponent & normalise value */
159
 
160
  /* If value > 1, then shrink it */
161
  if (value >= 1.0)
162
  {
163
    for (j = 0; j < 6; j++)
164
    {
165
      while (value >= powers[j].pvalue)
166
      {
167
        value /= powers[j].pvalue;
168
        texp += powers[j].exp;
169
      }
170
    }
171
  }
172
  else if (value != 0.0)
173
  {
174
    for (j = 0; j < 6; j++)
175
    {
176
      while (value <= powers[j].nvalue)
177
      {
178
        value *= powers[j].pvalue;
179
        texp -= powers[j].exp;
180
      }
181
    }
182
  }
183
   }
184
 
185
  else
186
  {
187
    texp = 0;
188
  }
189
 
190
 
191
  in->exp = texp;
192
  in->value = value;
193
  in->original_value = value;
194
  renormalize(in);
195
 
196
}
197
int
198
_DEFUN(round,(in, start, now, ch),
199
       cvt_info_type *in _AND
200
       char *start _AND
201
       char *now _AND
202
       char ch)
203
{
204
  double rounder = 5.0;
205
 
206
  char *p;
207
  int ok = 0;
208
 
209
  now --;
210
 
211
  /* If the next digit to output would have been a '5' run back and */
212
  /* see if we can create a more rounded number. If we can then do it.
213
     If not (like when the number was 9.9 and the last char was
214
     another 9), then we'll have to modify the number and try again */
215
  if (ch < '5')
216
   return 0;
217
 
218
 
219
  for (p = now;!ok && p >= start; p--)
220
  {
221
    switch (*p)
222
    {
223
    default:
224
      abort();
225
    case '.':
226
      break;
227
    case '9':
228
      rounder = rounder * 0.1;
229
      break;
230
    case '8':
231
    case '7':
232
    case '6':
233
    case '5':
234
    case '4':
235
    case '3':
236
    case '2':
237
    case '1':
238
    case '0':
239
      p = now;
240
      while (1) {
241
          if (*p == '9') {
242
              *p = '0';
243
            }
244
          else if (*p != '.') {
245
              (*p)++;
246
              return 0;
247
            }
248
          p--;
249
        }
250
    }
251
 
252
  }
253
 
254
  /* Getting here means that we couldn't round the number in place
255
     textually - there have been all nines.
256
     We'll have to add to it and try the conversion again
257
     eg
258
     .99999[9] can't be rounded in place, so add
259
     .000005   to it giving:
260
     1.000004   we notice that the result is > 1 so add to exp and
261
     divide by 10
262
     .100004
263
     */
264
 
265
  in->original_value = in->value = in->original_value + rounder;
266
  normalize(in->original_value , in);
267
  return 1;
268
 
269
 
270
}
271
 
272
 
273
 
274
void
275
_DEFUN(_cvte,(in),
276
       register  cvt_info_type *in)
277
{
278
  int buffer_idx  =0;
279
  int digit = 0;
280
 
281
  int after_decimal =0;
282
 
283
  in->buffer[buffer_idx++] = nextdigit(&(in->value));
284
  digit++;
285
  in->dot_idx = buffer_idx;
286
 
287
 
288
  switch (in->dot)
289
  {
290
  case dot_never:
291
    break;
292
  case dot_sometimes:
293
    if (in->decimal_places
294
        && digit < in->max_digits)
295
    {
296
      in->buffer[buffer_idx++] = '.';
297
    }
298
    break;
299
  case dot_always:
300
    in->buffer[buffer_idx++] = '.';
301
  }
302
 
303
 
304
  while (buffer_idx < in->buffer_size
305
         && after_decimal < in->decimal_places
306
         && digit < in->max_digits)
307
  {
308
    in->buffer[buffer_idx] = nextdigit(&(in->value));
309
    after_decimal++;
310
    buffer_idx++;
311
    digit++;
312
 
313
  }
314
 
315
  if (round(in,
316
            in->buffer,
317
            in->buffer+buffer_idx,
318
            nextdigit(&(in->value))))
319
  {
320
    _cvte(in);
321
  }
322
  else
323
  {
324
    in->buffer[buffer_idx++] = in->type;
325
    in->buffer[buffer_idx++] = in->abs_exp_sign;
326
 
327
    if (in->abs_exp >= 100)
328
    {
329
      in->buffer[buffer_idx++] = lcset[in->abs_exp / 100];
330
      in->abs_exp %= 100;
331
    }
332
    in->buffer[buffer_idx++] = lcset[in->abs_exp / 10];
333
    in->buffer[buffer_idx++] = lcset[in->abs_exp % 10];
334
  }
335
 
336
  in->buffer[buffer_idx++] = 0;
337
}
338
 
339
 
340
 
341
 
342
/* Produce NNNN.FFFF */
343
void
344
_DEFUN(_cvtf,(in),
345
       cvt_info_type *in)
346
{
347
 
348
  int buffer_idx = 0;            /* Current char being output */
349
  int after_decimal = 0;
350
  int digit =0;
351
 
352
 
353
  in->dot_idx = in->exp + 1;
354
 
355
  /* Two sorts of number, NNN.FFF and 0.0000...FFFF */
356
 
357
 
358
  /* Print all the digits up to the decimal point */
359
 
360
  while (buffer_idx <= in->exp
361
         && digit < in->max_digits
362
         && buffer_idx < in->buffer_size)
363
  {
364
    in->buffer[buffer_idx]  = nextdigit(&(in->value));
365
    buffer_idx++;
366
    digit ++;
367
  }
368
 
369
 
370
  /* And the decimal point if we should */
371
  if (buffer_idx < in->buffer_size)
372
  {
373
 
374
    switch (in->dot)
375
    {
376
    case dot_never:
377
      break;
378
    case dot_sometimes:
379
      /* Only print a dot if following chars */
380
      if (in->decimal_places
381
          && digit < in->max_digits )
382
      {
383
       in->buffer[buffer_idx++] = '.';
384
     }
385
 
386
      break;
387
    case dot_always:
388
      in->buffer[buffer_idx++] = '.';
389
    }
390
 
391
    after_decimal = 0;
392
 
393
    /* And the digits following the point if necessary */
394
 
395
    /* Only print the leading zeros if a dot was possible */
396
    if (in->dot || in->exp>0)
397
    {
398
     while (buffer_idx < in->buffer_size
399
            && (in->abs_exp_sign == '-' && digit < in->abs_exp - 1)
400
            && (after_decimal < in->decimal_places)
401
            && (digit < in->max_digits))
402
     {
403
       in->buffer[buffer_idx] = '0';
404
       buffer_idx++;
405
       digit++;
406
       after_decimal++;
407
     }
408
   }
409
 
410
    while (buffer_idx < in->buffer_size
411
           && after_decimal < in->decimal_places
412
           && digit < in->max_digits)
413
    {
414
      in->buffer[buffer_idx]  = nextdigit(&(in->value));
415
      buffer_idx++;
416
      digit++;
417
      after_decimal++;
418
    }
419
  }
420
 
421
  in->null_idx = buffer_idx;
422
  in->buffer[buffer_idx] = 0;
423
  if (round(in, in->buffer, in->buffer+buffer_idx,
424
            nextdigit(&(in->value))))
425
  {
426
      _cvtf(in);
427
  }
428
 
429
 
430
 
431
 
432
}
433
 
434
 
435
 
436
char *
437
_DEFUN(_dcvt,(buffer, invalue, precision, width, type, dot),
438
       char *buffer _AND
439
       double invalue _AND
440
       int precision _AND
441
       int width _AND
442
       char type _AND
443
       int dot)
444
{
445
  cvt_info_type in;
446
 
447
 
448
 
449
  in.buffer = buffer;
450
  in.buffer_size = 512;
451
 
452
  if (!finite(invalue))
453
  {
454
    return print_nan(buffer, invalue, precision);
455
  }
456
 
457
 
458
  normalize(invalue, &in);
459
 
460
  in.type = type;
461
  in.dot = dot? dot_always: dot_sometimes;
462
 
463
  switch (type)
464
  {
465
 
466
  case 'g':
467
  case 'G':
468
    /* When formatting a g, the precision refers to the number of
469
       char positions *total*, this leads to various off by ones */
470
  {
471
    /* A precision of 0 means 1 */
472
    if (precision == 0)
473
     precision = 1;
474
 
475
    /* A g turns into an e if there are more digits than the
476
       precision, or it's smaller than e-4 */
477
    if (in.exp >= precision || in.exp < -4)
478
    {
479
      in.type = (type == 'g' ? 'e' : 'E');
480
      in.decimal_places = _MAX_CHARS;
481
      in.max_digits = precision;
482
      in.print_trailing_zeros = 1;
483
      _cvte(&in);
484
    }
485
    else
486
    {
487
      /* G means total number of chars to print */
488
      in.decimal_places = _MAX_CHARS;
489
      in.max_digits = precision;
490
      in.type = (type == 'g' ? 'f' : 'F');
491
      in.print_trailing_zeros = 0;
492
      _cvtf(&in);
493
 
494
   if (!dot) {
495
       /* trim trailing zeros */
496
       int j = in.null_idx -1;
497
       while (j > 0 && in.buffer[j] == '0')
498
       {
499
         in.buffer[j] = 0;
500
         j--;
501
       }
502
       /* Stamp on a . if not followed by zeros */
503
       if (j > 0 && buffer[j] == '.')
504
        in.buffer[j] = 0;
505
     }
506
    }
507
 
508
 
509
    break;
510
  case 'f':
511
  case 'F':
512
    in.decimal_places= precision;
513
    in.max_digits = _MAX_CHARS;
514
      in.print_trailing_zeros = 1;
515
    _cvtf(&in);
516
    break;
517
  case 'e':
518
  case 'E':
519
      in.print_trailing_zeros = 1;
520
    in.decimal_places = precision;
521
    in.max_digits = _MAX_CHARS;
522
    _cvte(&in);
523
    break;
524
  }
525
 
526
  }
527
 
528
 
529
  return buffer;
530
}
531
 
532
 
533
 
534
 
535
char *
536
_DEFUN(fcvtbuf,(invalue,ndigit,decpt,sign, fcvt_buf),
537
       double invalue _AND
538
       int ndigit _AND
539
       int *decpt _AND
540
       int *sign _AND
541
       char *fcvt_buf)
542
{
543
  cvt_info_type in;
544
  in.buffer = fcvt_buf;
545
  in.buffer_size = 512;
546
 
547
  if (!finite(invalue))
548
    {
549
      return print_nan(fcvt_buf, invalue, ndigit);
550
    }
551
 
552
  normalize(invalue, &in);
553
 
554
  in.dot = dot_never;                   /* Don't print a decimal point */
555
  in.max_digits = _MAX_CHARS;
556
  in.buffer_size = _MAX_CHARS;          /* Take as many as needed */
557
  in.decimal_places = ndigit;
558
  _cvtf(&in);
559
  *decpt = in.dot_idx;
560
  *sign = in.value_neg;
561
  return in.buffer;
562
}
563
 
564
 
565
char *
566
_DEFUN(ecvtbuf,(invalue,ndigit,decpt,sign, fcvt_buf),
567
       double invalue _AND
568
       int ndigit _AND
569
       int *decpt _AND
570
       int *sign _AND
571
       char *fcvt_buf)
572
{
573
  cvt_info_type in;
574
  in.buffer = fcvt_buf;
575
 
576
  if (!finite(invalue))
577
    {
578
      return print_nan(fcvt_buf, invalue, ndigit);
579
    }
580
 
581
  normalize(invalue, &in);
582
 
583
 
584
  in.dot = dot_never;                   /* Don't print a decimal point */
585
/* We can work out how many digits go after the decimal point */
586
 
587
  in.buffer_size =_MAX_CHARS;
588
  in.decimal_places = _MAX_CHARS;
589
  in.max_digits = ndigit;               /* Take as many as told */
590
  _cvtf(&in);
591
  *decpt = in.dot_idx;
592
  *sign = in.value_neg;
593
  return in.buffer;
594
}
595
 
596
 
597
 
598
char *
599
_DEFUN(gcvt,(d,ndigit,buf),
600
   double d _AND
601
   int ndigit _AND
602
   char *buf)
603
{
604
  return _dcvt(buf, d, ndigit, 0, 'g', 1);
605
}

powered by: WebSVN 2.1.0

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