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 /****************************************************************************/ 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 /****************************************************************************/ 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 /****************************************************************************/ 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 /****************************************************************************/ 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