Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
MorsGames
GitHub Repository: MorsGames/sm64plus
Path: blob/master/lib/src/_Ldtob.c
7857 views
1
#include "libultra_internal.h"
2
#include <macros.h>
3
#include <stdlib.h>
4
#include <string.h>
5
#include "printf.h"
6
7
#define BUFF_LEN 0x20
8
9
static s16 _Ldunscale(s16 *, printf_struct *);
10
static void _Genld(printf_struct *, u8, u8 *, s16, s16);
11
12
const double D_80338670[] = { 10e0L, 10e1L, 10e3L, 10e7L, 10e15L, 10e31L, 10e63L, 10e127L, 10e255L };
13
14
/* float properties */
15
#define _D0 0
16
#define _DBIAS 0x3ff
17
#define _DLONG 1
18
#define _DOFF 4
19
#define _FBIAS 0x7e
20
#define _FOFF 7
21
#define _FRND 1
22
#define _LBIAS 0x3ffe
23
#define _LOFF 15
24
/* integer properties */
25
#define _C2 1
26
#define _CSIGN 1
27
#define _ILONG 0
28
#define _MBMAX 8
29
#define NAN 2
30
#define INF 1
31
#define FINITE -1
32
#define _DFRAC ((1 << _DOFF) - 1)
33
#define _DMASK (0x7fff & ~_DFRAC)
34
#define _DMAX ((1 << (15 - _DOFF)) - 1)
35
#define _DNAN (0x8000 | _DMAX << _DOFF | 1 << (_DOFF - 1))
36
#define _DSIGN 0x8000
37
#if _D0 == 3
38
#define _D1 2 /* little-endian order */
39
#define _D2 1
40
#define _D3 0
41
#else
42
#define _D1 1 /* big-endian order */
43
#define _D2 2
44
#define _D3 3
45
#endif
46
47
void _Ldtob(printf_struct *args, u8 type) {
48
u8 buff[BUFF_LEN];
49
u8 *ptr;
50
UNUSED u32 sp70;
51
f64 val;
52
/* maybe struct? */
53
s16 err;
54
s16 nsig;
55
s16 exp;
56
57
s32 i;
58
s32 n;
59
f64 factor;
60
s32 gen;
61
s32 j;
62
s32 lo;
63
ldiv_t qr;
64
u8 drop;
65
s32 n2;
66
/* */
67
UNUSED u8 unused[0x4];
68
ptr = buff;
69
val = args->value.f64;
70
if (args->precision < 0) {
71
args->precision = 6;
72
} else {
73
if (args->precision == 0 && (type == 'g' || type == 'G')) {
74
args->precision = 1;
75
}
76
}
77
err = _Ldunscale(&exp, args);
78
if (err > 0) {
79
memcpy(args->buff, err == 2 ? "NaN" : "Inf", args->part2_len = 3);
80
return;
81
}
82
if (err == 0) {
83
nsig = 0;
84
exp = 0;
85
} else {
86
if (val < 0) {
87
val = -val;
88
}
89
exp = exp * 30103 / 0x000186A0 - 4;
90
if (exp < 0) {
91
n = (3 - exp) & ~3;
92
exp = -n;
93
for (i = 0; n > 0; n >>= 1, i++) {
94
if ((n & 1) != 0) {
95
val *= D_80338670[i];
96
}
97
}
98
} else {
99
if (exp > 0) {
100
factor = 1;
101
exp &= ~3;
102
for (n = exp, i = 0; n > 0; n >>= 1, i++) {
103
if ((n & 1) != 0) {
104
factor *= D_80338670[i];
105
}
106
}
107
val /= factor;
108
}
109
}
110
gen = ((type == 'f') ? exp + 10 : 6) + args->precision;
111
if (gen > 0x13) {
112
gen = 0x13;
113
}
114
*ptr++ = '0';
115
while (gen > 0 && 0 < val) {
116
lo = val;
117
if ((gen -= 8) > 0) {
118
val = (val - lo) * 1.0e8;
119
}
120
ptr = ptr + 8;
121
for (j = 8; lo > 0 && --j >= 0;) {
122
qr = ldiv(lo, 10);
123
*--ptr = qr.rem + '0';
124
lo = qr.quot;
125
}
126
while (--j >= 0) {
127
ptr--;
128
*ptr = '0';
129
}
130
ptr += 8;
131
}
132
133
gen = ptr - &buff[1];
134
for (ptr = &buff[1], exp += 7; *ptr == '0'; ptr++) {
135
--gen, --exp;
136
}
137
138
nsig = ((type == 'f') ? exp + 1 : ((type == 'e' || type == 'E') ? 1 : 0)) + args->precision;
139
if (gen < nsig) {
140
nsig = gen;
141
}
142
if (nsig > 0) {
143
if (nsig < gen && ptr[nsig] > '4') {
144
drop = '9';
145
} else {
146
drop = '0';
147
}
148
149
for (n2 = nsig; ptr[--n2] == drop;) {
150
nsig--;
151
}
152
if (drop == '9') {
153
ptr[n2]++;
154
}
155
if (n2 < 0) {
156
--ptr, ++nsig, ++exp;
157
}
158
}
159
}
160
_Genld(args, type, ptr, nsig, exp);
161
}
162
163
static s16 _Ldunscale(s16 *pex, printf_struct *px) {
164
165
unsigned short *ps = (unsigned short *) px;
166
short xchar = (ps[_D0] & _DMASK) >> _DOFF;
167
if (xchar == _DMAX) { /* NaN or INF */
168
*pex = 0;
169
return (s16)(ps[_D0] & _DFRAC || ps[_D1] || ps[_D2] || ps[_D3] ? NAN : INF);
170
} else if (0 < xchar) {
171
ps[_D0] = (ps[_D0] & ~_DMASK) | (_DBIAS << _DOFF);
172
*pex = xchar - (_DBIAS - 1);
173
return (FINITE);
174
}
175
if (0 > xchar) {
176
return NAN;
177
} else {
178
*pex = 0;
179
return (0);
180
}
181
}
182
183
static void _Genld(printf_struct *px, u8 code, u8 *p, s16 nsig, s16 xexp) {
184
u8 point = '.';
185
if (nsig <= 0) {
186
nsig = 1,
187
188
p = (u8 *) "0";
189
}
190
191
if (code == 'f'
192
|| ((code == 'g' || code == 'G') && (-4 <= xexp) && (xexp < px->precision))) { /* 'f' format */
193
++xexp; /* change to leading digit count */
194
if (code != 'f') { /* fixup for 'g' */
195
if (!(px->flags & FLAGS_HASH) && nsig < px->precision) {
196
px->precision = nsig;
197
}
198
if ((px->precision -= xexp) < 0) {
199
px->precision = 0;
200
}
201
}
202
if (xexp <= 0) { /* digits only to right of point */
203
px->buff[px->part2_len++] = '0';
204
if (0 < px->precision || px->flags & FLAGS_HASH) {
205
px->buff[px->part2_len++] = point;
206
}
207
if (px->precision < -xexp) {
208
xexp = -px->precision;
209
}
210
px->num_mid_zeros = -xexp;
211
px->precision += xexp;
212
if (px->precision < nsig) {
213
nsig = px->precision;
214
}
215
memcpy(&px->buff[px->part2_len], p, px->part3_len = nsig);
216
px->num_trailing_zeros = px->precision - nsig;
217
} else if (nsig < xexp) { /* zeros before point */
218
memcpy(&px->buff[px->part2_len], p, nsig);
219
px->part2_len += nsig;
220
px->num_mid_zeros = xexp - nsig;
221
if (0 < px->precision || px->flags & FLAGS_HASH) {
222
px->buff[px->part2_len] = point, ++px->part3_len;
223
}
224
px->num_trailing_zeros = px->precision;
225
} else { /* enough digits before point */
226
memcpy(&px->buff[px->part2_len], p, xexp);
227
px->part2_len += xexp;
228
nsig -= xexp;
229
if (0 < px->precision || px->flags & FLAGS_HASH) {
230
px->buff[px->part2_len++] = point;
231
}
232
if (px->precision < nsig) {
233
nsig = px->precision;
234
}
235
memcpy(&px->buff[px->part2_len], p + xexp, nsig);
236
px->part2_len += nsig;
237
px->num_mid_zeros = px->precision - nsig;
238
}
239
} else { /* 'e' format */
240
if (code == 'g' || code == 'G') { /* fixup for 'g' */
241
if (nsig < px->precision) {
242
px->precision = nsig;
243
}
244
if (--px->precision < 0) {
245
px->precision = 0;
246
}
247
code = code == 'g' ? 'e' : 'E';
248
}
249
px->buff[px->part2_len++] = *p++;
250
if (0 < px->precision || px->flags & FLAGS_HASH) {
251
px->buff[px->part2_len++] = point;
252
}
253
if (0 < px->precision) { /* put fraction digits */
254
if (px->precision < --nsig) {
255
nsig = px->precision;
256
}
257
memcpy(&px->buff[px->part2_len], p, nsig);
258
px->part2_len += nsig;
259
px->num_mid_zeros = px->precision - nsig;
260
}
261
p = (u8 *) &px->buff[px->part2_len]; /* put exponent */
262
*p++ = code;
263
if (0 <= xexp) {
264
*p++ = '+';
265
} else { /* negative exponent */
266
*p++ = '-';
267
xexp = -xexp;
268
}
269
if (100 <= xexp) { /* put oversize exponent */
270
if (1000 <= xexp) {
271
*p++ = xexp / 1000 + '0', xexp %= 1000;
272
}
273
*p++ = xexp / 100 + '0', xexp %= 100;
274
}
275
*p++ = xexp / 10 + '0', xexp %= 10;
276
*p++ = xexp + '0';
277
px->part3_len = p - (u8 *) &px->buff[px->part2_len];
278
}
279
if ((px->flags & (FLAGS_ZERO | FLAGS_MINUS)) == FLAGS_ZERO) { /* pad with leading zeros */
280
int n =
281
px->part1_len + px->part2_len + px->num_mid_zeros + px->part3_len + px->num_trailing_zeros;
282
283
if (n < px->width) {
284
px->num_leading_zeros = px->width - n;
285
}
286
}
287
}
288
289