annotate src/libsys/sprintf/float.c @ 0:92470e5d0b9e

src: partial import from FC Selenite
author Mychaela Falconia <falcon@freecalypso.org>
date Fri, 15 May 2020 01:28:16 +0000
parents
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
1 /*
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
2 * Embedded [v]sprintf() implementation by Mychaela Falconia,
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
3 * loosely based on the 4.3BSD-Tahoe version.
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
4 *
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
5 * This module contains the floating point conversion functions.
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
6 */
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
7
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
8 #include <sys/types.h>
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
9 #include <ctype.h>
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
10 #include "defs.h"
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
11
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
12 extern double modf();
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
13
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
14 extern u_char * _sprintf_field(u_char *op, int width, int flags, int sign,
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
15 u_char *body, int size, int dprec, int fpprec);
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
16
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
17 #define MAX_INT_DIGITS 10 /* 2^32-1 in decimal */
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
18 #define MAXFRACT 16 /* max sensible for 64-bit double */
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
19 #define DEFPREC 6
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
20
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
21 static char *
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
22 emit_integer_portion(unsigned number, char *endp)
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
23 {
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
24 char *t = endp;
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
25
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
26 do {
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
27 *--t = tochar(number % 10);
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
28 number /= 10;
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
29 } while (number);
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
30 return (t);
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
31 }
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
32
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
33 static int
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
34 f_round(double fract, char *start, char *end, int sign)
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
35 {
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
36 double tmp;
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
37
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
38 (void)modf(fract * 10, &tmp);
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
39 if (tmp > 4)
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
40 for (;; --end) {
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
41 if (*end == '.')
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
42 --end;
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
43 if (++*end <= '9')
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
44 break;
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
45 *end = '0';
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
46 if (end == start) {
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
47 *--end = '1';
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
48 return(1);
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
49 }
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
50 }
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
51 /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
52 else if (sign == '-')
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
53 for (;; --end) {
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
54 if (*end == '.')
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
55 --end;
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
56 if (*end != '0')
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
57 break;
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
58 if (end == start)
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
59 return(-1); /* clear the -ve */
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
60 }
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
61 return(0);
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
62 }
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
63
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
64 u_char *
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
65 _sprintf_percent_f(u_char *op, int width, int flags, int sign,
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
66 double number, int prec)
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
67 {
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
68 char buf[MAX_INT_DIGITS + 1 + MAXFRACT];
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
69 int extra_prec = 0;
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
70 int origsign = sign;
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
71 int round_stat;
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
72 double fract, tmp;
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
73 char *start, *t;
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
74
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
75 /* first order of business: weed out infinities and NaNs */
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
76 if (isinf(number)) {
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
77 if (number < 0)
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
78 sign = '-';
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
79 return _sprintf_field(op, width, flags, sign, "Inf", 3, 0, 0);
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
80 }
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
81 if (isnan(number))
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
82 return _sprintf_field(op, width, flags, sign, "NaN", 3, 0, 0);
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
83 /* OK, we know it's a valid real like in the good old VAX days */
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
84 if (number < 0) {
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
85 sign = '-';
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
86 number = -number;
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
87 }
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
88 fract = modf(number, &tmp);
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
89 if (tmp > (double) 0xFFFFFFFF)
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
90 return _sprintf_field(op, width, flags, sign, "Toobig", 6,
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
91 0, 0);
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
92 start = emit_integer_portion((unsigned) tmp, buf + MAX_INT_DIGITS);
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
93 if (prec > MAXFRACT) {
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
94 extra_prec = prec - MAXFRACT;
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
95 prec = MAXFRACT;
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
96 } else if (prec == -1)
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
97 prec = DEFPREC;
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
98 t = buf + MAX_INT_DIGITS;
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
99 /*
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
100 * if precision required or alternate flag set, add in a
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
101 * decimal point.
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
102 */
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
103 if (prec || flags&ALT)
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
104 *t++ = '.';
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
105 /* if requires more precision and some fraction left */
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
106 if (fract) {
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
107 if (prec)
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
108 do {
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
109 fract = modf(fract * 10, &tmp);
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
110 *t++ = tochar((int)tmp);
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
111 } while (--prec && fract);
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
112 if (fract) {
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
113 round_stat = f_round(fract, start, t - 1, sign);
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
114 if (round_stat == 1)
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
115 start--;
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
116 else if (round_stat == -1)
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
117 sign = origsign;
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
118 }
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
119 }
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
120 return _sprintf_field(op, width, flags, sign, start, t - start,
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
121 0, prec + extra_prec);
92470e5d0b9e src: partial import from FC Selenite
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff changeset
122 }