1
2 /*
3 * M_APM - mapm_fpf.c
4 *
5 * Copyright (C) 2001 - 2007 Michael C. Ring
6 *
7 * Permission to use, copy, and distribute this software and its
8 * documentation for any purpose with or without fee is hereby granted,
9 * provided that the above copyright notice appear in all copies and
10 * that both that copyright notice and this permission notice appear
11 * in supporting documentation.
12 *
13 * Permission to modify the software is granted. Permission to distribute
14 * the modified code is granted. Modifications are to be distributed by
15 * using the file 'license.txt' as a template to modify the file header.
16 * 'license.txt' is available in the official MAPM distribution.
17 *
18 * This software is provided "as is" without express or implied warranty.
19 */
20
21 /*
22 * $Id: mapm_fpf.c,v 1.10 2007/12/03 01:39:57 mike Exp $
23 *
24 * This file contains the Fixed Point Formatting functions
25 *
26 * $Log: mapm_fpf.c,v $
27 * Revision 1.10 2007/12/03 01:39:57 mike
28 * Update license
29 *
30 * Revision 1.9 2003/07/21 20:15:12 mike
31 * Modify error messages to be in a consistent format.
32 *
33 * Revision 1.8 2003/03/31 22:11:14 mike
34 * call generic error handling function
35 *
36 * Revision 1.7 2002/11/05 23:31:00 mike
37 * use new set_to_zero call instead of copy
38 *
39 * Revision 1.6 2002/11/03 22:33:24 mike
40 * Updated function parameters to use the modern style
41 *
42 * Revision 1.5 2002/02/14 19:31:44 mike
43 * eliminate need for conditional compile
44 *
45 * Revision 1.4 2001/08/26 22:35:50 mike
46 * no LCC conditional needed on fixpt_string
47 *
48 * Revision 1.3 2001/08/26 22:11:10 mike
49 * add new 'stringexp' function
50 *
51 * Revision 1.2 2001/08/25 22:30:09 mike
52 * fix LCC-WIN32 compile problem
53 *
54 * Revision 1.1 2001/08/25 16:50:59 mike
55 * Initial revision
56 */
57
58 #include "m_apm_lc.h"
59 #include <ctype.h>
60
61 /****************************************************************************/
m_apm_to_fixpt_stringexp(int dplaces,M_APM atmp,char ch_radx,char ch_sep,int ct_sep)62 char *m_apm_to_fixpt_stringexp(int dplaces, M_APM atmp,
63 char ch_radx, char ch_sep, int ct_sep)
64 {
65 int places, xp, dl, ii;
66 char *cpr;
67
68 places = dplaces;
69
70 dl = atmp->m_apm_datalength;
71 xp = atmp->m_apm_exponent;
72
73 if (places < 0) /* show ALL digits */
74 {
75 if (xp < 0)
76 ii = dl - xp;
77 else
78 {
79 if (dl > xp)
80 ii = dl;
81 else
82 ii = xp;
83 }
84 }
85 else
86 {
87 ii = places;
88
89 if (xp > 0)
90 ii += xp;
91 }
92
93 if (ct_sep != 0 && ch_sep != 0 && xp > 0)
94 ii += xp / ct_sep;
95
96 if ((cpr = (char *)MAPM_MALLOC((ii + 32) * sizeof(char))) == NULL)
97 return(NULL);
98
99 m_apm_to_fixpt_stringex(cpr,places,atmp,ch_radx,ch_sep,ct_sep);
100
101 return(cpr);
102 }
103 /****************************************************************************/
m_apm_to_fixpt_stringex(char * s,int dplaces,M_APM atmp,char ch_radix,char ch_sep,int count_sep)104 void m_apm_to_fixpt_stringex(char *s, int dplaces, M_APM atmp,
105 char ch_radix, char ch_sep, int count_sep)
106 {
107 M_APM btmp;
108 char ch, *cpd, *cps;
109 int ii, jj, kk, ct, dl, xp, no_sep_flg, places;
110
111 btmp = M_get_stack_var();
112 places = dplaces;
113 cpd = s;
114 no_sep_flg = FALSE;
115
116 m_apm_absolute_value(btmp, atmp); /* do conversion of positive number */
117
118 if (ch_sep == 0 || count_sep == 0) /* no separator char OR count */
119 no_sep_flg = TRUE;
120
121 /* determine how much memory to get for the temp string */
122
123 dl = btmp->m_apm_datalength;
124 xp = btmp->m_apm_exponent;
125
126 if (places < 0) /* show ALL digits */
127 {
128 if (xp < 0)
129 ii = dl - xp;
130 else
131 {
132 if (dl > xp)
133 ii = dl;
134 else
135 ii = xp;
136 }
137 }
138 else
139 {
140 ii = places;
141
142 if (xp > 0)
143 ii += xp;
144 }
145
146 if ((cps = (char *)MAPM_MALLOC((ii + 32) * sizeof(char))) == NULL)
147 {
148 /* fatal, this does not return */
149
150 M_apm_log_error_msg(M_APM_FATAL,
151 "\'m_apm_to_fixpt_stringex\', Out of memory");
152 }
153
154 m_apm_to_fixpt_string(cps, places, btmp);
155
156 /*
157 * the converted string may be all 'zero', 0.0000...
158 * if so and the original number is negative,
159 * do NOT set the '-' sign of our output string.
160 */
161
162 if (atmp->m_apm_sign == -1) /* if input number negative */
163 {
164 kk = 0;
165 jj = 0;
166
167 while (TRUE)
168 {
169 ch = cps[kk++];
170 if ((ch == '\0') || (jj != 0))
171 break;
172
173 if (isdigit((int)ch))
174 {
175 if (ch != '0')
176 jj = 1;
177 }
178 }
179
180 if (jj)
181 *cpd++ = '-';
182 }
183
184 ct = M_strposition(cps, "."); /* find the default (.) radix char */
185
186 if (ct == -1) /* if not found .. */
187 {
188 strcat(cps, "."); /* add one */
189 ct = M_strposition(cps, "."); /* and then find it */
190 }
191
192 if (places == 0) /* int format, terminate at radix char */
193 cps[ct] = '\0';
194 else
195 cps[ct] = ch_radix; /* assign the radix char */
196
197 /*
198 * if the number is small enough to not have any separator char's ...
199 */
200
201 if (ct <= count_sep)
202 no_sep_flg = TRUE;
203
204 if (no_sep_flg)
205 {
206 strcpy(cpd, cps);
207 }
208 else
209 {
210 jj = 0;
211 kk = count_sep;
212 ii = ct / count_sep;
213
214 if ((ii = ct - ii * count_sep) == 0)
215 ii = count_sep;
216
217 while (TRUE) /* write out the first 1,2 */
218 { /* (up to count_sep) digits */
219 *cpd++ = cps[jj++];
220
221 if (--ii == 0)
222 break;
223 }
224
225 while (TRUE) /* write rest of the string */
226 {
227 if (kk == count_sep) /* write a new separator char */
228 {
229 if (jj != ct) /* unless we're at the radix */
230 {
231 *cpd++ = ch_sep; /* note that this also disables */
232 kk = 0; /* the separator char AFTER */
233 } /* the radix char */
234 }
235
236 if ((*cpd++ = cps[jj++]) == '\0')
237 break;
238
239 kk++;
240 }
241 }
242
243 MAPM_FREE(cps);
244 M_restore_stack(1);
245 }
246 /****************************************************************************/
m_apm_to_fixpt_string(char * ss,int dplaces,M_APM mtmp)247 void m_apm_to_fixpt_string(char *ss, int dplaces, M_APM mtmp)
248 {
249 M_APM ctmp;
250 void *vp;
251 int places, i2, ii, jj, kk, xp, dl, numb;
252 UCHAR *ucp, numdiv, numrem;
253 char *cpw, *cpd, sbuf[128];
254
255 ctmp = M_get_stack_var();
256 vp = NULL;
257 cpd = ss;
258 places = dplaces;
259
260 /* just want integer portion if places == 0 */
261
262 if (places == 0)
263 {
264 if (mtmp->m_apm_sign >= 0)
265 m_apm_add(ctmp, mtmp, MM_0_5);
266 else
267 m_apm_subtract(ctmp, mtmp, MM_0_5);
268
269 m_apm_to_integer_string(cpd, ctmp);
270
271 M_restore_stack(1);
272 return;
273 }
274
275 if (places > 0)
276 M_apm_round_fixpt(ctmp, places, mtmp);
277 else
278 m_apm_copy(ctmp, mtmp); /* show ALL digits */
279
280 if (ctmp->m_apm_sign == 0) /* result is 0 */
281 {
282 if (places < 0)
283 {
284 cpd[0] = '0'; /* "0.0" */
285 cpd[1] = '.';
286 cpd[2] = '0';
287 cpd[3] = '\0';
288 }
289 else
290 {
291 memset(cpd, '0', (places + 2)); /* pre-load string with all '0' */
292 cpd[1] = '.';
293 cpd[places + 2] = '\0';
294 }
295
296 M_restore_stack(1);
297 return;
298 }
299
300 xp = ctmp->m_apm_exponent;
301 dl = ctmp->m_apm_datalength;
302 numb = (dl + 1) >> 1;
303
304 if (places < 0)
305 {
306 if (dl > xp)
307 jj = dl + 16;
308 else
309 jj = xp + 16;
310 }
311 else
312 {
313 jj = places + 16;
314
315 if (xp > 0)
316 jj += xp;
317 }
318
319 if (jj > 112)
320 {
321 if ((vp = (void *)MAPM_MALLOC((jj + 16) * sizeof(char))) == NULL)
322 {
323 /* fatal, this does not return */
324
325 M_apm_log_error_msg(M_APM_FATAL,
326 "\'m_apm_to_fixpt_string\', Out of memory");
327 }
328
329 cpw = (char *)vp;
330 }
331 else
332 {
333 cpw = sbuf;
334 }
335
336 /*
337 * at this point, the number is non-zero and the the output
338 * string will contain at least 1 significant digit.
339 */
340
341 if (ctmp->m_apm_sign == -1) /* negative number */
342 {
343 *cpd++ = '-';
344 }
345
346 ucp = ctmp->m_apm_data;
347 ii = 0;
348
349 /* convert MAPM num to ASCII digits and store in working char array */
350
351 while (TRUE)
352 {
353 M_get_div_rem_10((int)(*ucp++), &numdiv, &numrem);
354
355 cpw[ii++] = numdiv + '0';
356 cpw[ii++] = numrem + '0';
357
358 if (--numb == 0)
359 break;
360 }
361
362 i2 = ii; /* save for later */
363
364 if (places < 0) /* show ALL digits */
365 {
366 places = dl - xp;
367
368 if (places < 1)
369 places = 1;
370 }
371
372 /* pad with trailing zeros if needed */
373
374 kk = xp + places + 2 - ii;
375
376 if (kk > 0)
377 memset(&cpw[ii], '0', kk);
378
379 if (xp > 0) /* |num| >= 1, NO lead-in "0.nnn" */
380 {
381 ii = xp + places + 1;
382 jj = 0;
383
384 for (kk=0; kk < ii; kk++)
385 {
386 if (kk == xp)
387 cpd[jj++] = '.';
388
389 cpd[jj++] = cpw[kk];
390 }
391
392 cpd[ii] = '\0';
393 }
394 else /* |num| < 1, have lead-in "0.nnn" */
395 {
396 jj = 2 - xp;
397 ii = 2 + places;
398 memset(cpd, '0', (ii + 1)); /* pre-load string with all '0' */
399 cpd[1] = '.'; /* assign decimal point */
400
401 for (kk=0; kk < i2; kk++)
402 {
403 cpd[jj++] = cpw[kk];
404 }
405
406 cpd[ii] = '\0';
407 }
408
409 if (vp != NULL)
410 MAPM_FREE(vp);
411
412 M_restore_stack(1);
413 }
414 /****************************************************************************/
M_apm_round_fixpt(M_APM btmp,int places,M_APM atmp)415 void M_apm_round_fixpt(M_APM btmp, int places, M_APM atmp)
416 {
417 int xp, ii;
418
419 xp = atmp->m_apm_exponent;
420 ii = xp + places - 1;
421
422 M_set_to_zero(btmp); /* assume number is too small so the net result is 0 */
423
424 if (ii >= 0)
425 {
426 m_apm_round(btmp, ii, atmp);
427 }
428 else
429 {
430 if (ii == -1) /* next digit is significant which may round up */
431 {
432 if (atmp->m_apm_data[0] >= 50) /* digit >= 5, round up */
433 {
434 m_apm_copy(btmp, atmp);
435 btmp->m_apm_data[0] = 10;
436 btmp->m_apm_exponent += 1;
437 btmp->m_apm_datalength = 1;
438 M_apm_normalize(btmp);
439 }
440 }
441 }
442 }
443 /****************************************************************************/
444
445