5 * Copyright (C) 1999 - 2007 Michael C. Ring
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.
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.
18 * This software is provided "as is" without express or implied warranty.
22 * $Id: mapmutil.c,v 1.26 2007/12/03 01:58:49 mike Exp $
24 * This file contains various utility functions needed by the
25 * library in addition to some basic user callable functions.
27 * $Log: mapmutil.c,v $
28 * Revision 1.26 2007/12/03 01:58:49 mike
31 * Revision 1.25 2003/07/21 20:51:34 mike
32 * Modify error messages to be in a consistent format.
34 * Revision 1.24 2003/03/31 22:03:54 mike
35 * call generic error handling function
37 * Revision 1.23 2002/11/04 20:47:02 mike
38 * change m_apm_init so it compiles clean with a real C++ compiler
40 * Revision 1.22 2002/11/03 22:50:58 mike
41 * Updated function parameters to use the modern style
43 * Revision 1.21 2002/05/17 22:26:49 mike
44 * move some functions into another file
46 * Revision 1.20 2002/02/12 20:21:53 mike
47 * eliminate unneeded working arrays in _scale
48 * by processing the scaling operation in reverse
50 * Revision 1.19 2001/07/24 18:29:18 mike
51 * add util function to get address of
52 * the div/rem lookup tables
54 * Revision 1.18 2001/07/20 16:14:05 mike
55 * optimize normalize yet again
57 * Revision 1.17 2001/07/17 18:17:56 mike
58 * another optimization to _normalize
60 * Revision 1.16 2001/07/16 22:33:43 mike
61 * update free_all_util
63 * Revision 1.15 2001/07/16 19:56:26 mike
64 * add function M_free_all_util
66 * Revision 1.14 2001/07/16 18:10:21 mike
67 * optimize M_apm_normalize when moving multiple '00' bytes
69 * Revision 1.13 2001/02/11 22:36:43 mike
70 * modify parameters to REALLOC
72 * Revision 1.12 2001/01/23 21:17:38 mike
73 * add dedicated long->ascii conversion (instead of sprintf)
75 * Revision 1.11 2000/08/22 20:21:54 mike
76 * fix m_apm_exponent with exactly 0 as the input
78 * Revision 1.10 2000/08/22 00:01:26 mike
79 * add zero check in is_integer
81 * Revision 1.9 2000/08/21 23:34:44 mike
82 * add new function _is_integer
84 * Revision 1.8 2000/08/01 22:29:02 mike
85 * add sizeof int function call
87 * Revision 1.7 2000/05/19 16:21:03 mike
88 * delete M_check_dec_places, no longer needed
90 * Revision 1.6 2000/04/04 17:06:37 mike
91 * initialize C++ refcount struct element to 1
93 * Revision 1.5 2000/02/03 22:49:56 mike
94 * use MAPM_* generic memory function
96 * Revision 1.4 1999/09/18 03:06:41 mike
99 * Revision 1.3 1999/09/18 02:59:11 mike
100 * added new functions
102 * Revision 1.2 1999/05/15 02:21:14 mike
103 * add check for number of decimal places
105 * Revision 1.1 1999/05/10 20:56:31 mike
109 #include "m_apm_lc.h"
111 static UCHAR
*M_mul_div
= NULL
;
112 static UCHAR
*M_mul_rem
= NULL
;
114 static UCHAR M_mul_div_10
[100];
115 static UCHAR M_mul_rem_10
[100];
117 static int M_util_firsttime
= TRUE
;
118 static int M_firsttime3
= TRUE
;
120 static M_APM M_work_0_5
;
122 static char *M_init_error_msg
= "\'m_apm_init\', Out of memory";
124 /****************************************************************************/
131 M_firsttime3
= FALSE
;
133 M_init_trig_globals();
136 if ((atmp
= (M_APM
)MAPM_MALLOC(sizeof(M_APM_struct
))) == NULL
)
138 /* fatal, this does not return */
140 M_apm_log_error_msg(M_APM_FATAL
, M_init_error_msg
);
143 atmp
->m_apm_id
= M_APM_IDENT
;
144 atmp
->m_apm_malloclength
= 80;
145 atmp
->m_apm_datalength
= 1;
146 atmp
->m_apm_refcount
= 1; /* not for us, for MAPM C++ class */
147 atmp
->m_apm_exponent
= 0;
148 atmp
->m_apm_sign
= 0;
150 if ((atmp
->m_apm_data
= (UCHAR
*)MAPM_MALLOC(84)) == NULL
)
152 /* fatal, this does not return */
154 M_apm_log_error_msg(M_APM_FATAL
, M_init_error_msg
);
157 atmp
->m_apm_data
[0] = 0;
160 /****************************************************************************/
161 void m_apm_free(M_APM atmp
)
163 if (atmp
->m_apm_id
== M_APM_IDENT
)
165 atmp
->m_apm_id
= 0x0FFFFFF0L
;
166 MAPM_FREE(atmp
->m_apm_data
);
171 M_apm_log_error_msg(M_APM_RETURN
, "\'m_apm_free\', Invalid M_APM variable");
174 /****************************************************************************/
175 void M_free_all_util()
177 if (M_util_firsttime
== FALSE
)
179 m_apm_free(M_work_0_5
);
180 M_util_firsttime
= TRUE
;
183 if (M_firsttime3
== FALSE
)
185 MAPM_FREE(M_mul_div
);
186 MAPM_FREE(M_mul_rem
);
193 /****************************************************************************/
195 * just a dummy wrapper to keep some compilers from complaining
197 int M_get_sizeof_int()
201 /****************************************************************************/
202 void M_init_util_data()
207 if (M_mul_div
!= NULL
)
210 M_mul_div
= (UCHAR
*)MAPM_MALLOC(10000 * sizeof(UCHAR
));
211 M_mul_rem
= (UCHAR
*)MAPM_MALLOC(10000 * sizeof(UCHAR
));
213 if (M_mul_div
== NULL
|| M_mul_rem
== NULL
)
215 /* fatal, this does not return */
217 M_apm_log_error_msg(M_APM_FATAL
, "\'M_init_util_data\', Out of memory");
223 for (k
=0; k
< 100; k
++)
225 M_mul_div_10
[k
] = ndiv
;
226 M_mul_rem_10
[k
] = nrem
;
238 for (k
=0; k
< 10000; k
++)
250 /****************************************************************************/
251 void M_get_div_rem_addr(UCHAR
**ndivp
, UCHAR
**nremp
)
256 /****************************************************************************/
257 void M_get_div_rem(int tbl_lookup
, UCHAR
*ndiv
, UCHAR
*nrem
)
259 *ndiv
= M_mul_div
[tbl_lookup
];
260 *nrem
= M_mul_rem
[tbl_lookup
];
262 /****************************************************************************/
263 void M_get_div_rem_10(int tbl_lookup
, UCHAR
*ndiv
, UCHAR
*nrem
)
265 *ndiv
= M_mul_div_10
[tbl_lookup
];
266 *nrem
= M_mul_rem_10
[tbl_lookup
];
268 /****************************************************************************/
269 void m_apm_round(M_APM btmp
, int places
, M_APM atmp
)
273 if (M_util_firsttime
)
275 M_util_firsttime
= FALSE
;
277 M_work_0_5
= m_apm_init();
278 m_apm_set_string(M_work_0_5
, "5");
283 if (atmp
->m_apm_datalength
<= ii
)
285 m_apm_copy(btmp
,atmp
);
289 M_work_0_5
->m_apm_exponent
= atmp
->m_apm_exponent
- ii
;
291 if (atmp
->m_apm_sign
> 0)
292 m_apm_add(btmp
, atmp
, M_work_0_5
);
294 m_apm_subtract(btmp
, atmp
, M_work_0_5
);
296 btmp
->m_apm_datalength
= ii
;
297 M_apm_normalize(btmp
);
299 /****************************************************************************/
300 void M_apm_normalize(M_APM atmp
)
302 int i
, index
, datalength
, exponent
;
303 UCHAR
*ucp
, numdiv
, numrem
, numrem2
;
305 if (atmp
->m_apm_sign
== 0)
308 datalength
= atmp
->m_apm_datalength
;
309 exponent
= atmp
->m_apm_exponent
;
311 /* make sure trailing bytes/chars are 0 */
312 /* the following function will adjust the 'datalength' */
313 /* we want the original value and will fix it later */
315 M_apm_pad(atmp
, (datalength
+ 3));
317 while (TRUE
) /* remove lead-in '0' if any */
319 M_get_div_rem_10((int)atmp
->m_apm_data
[0], &numdiv
, &numrem
);
321 if (numdiv
>= 1) /* number is normalized, done here */
324 index
= (datalength
+ 1) >> 1;
326 if (numrem
== 0) /* both nibbles are 0, we can move full bytes */
329 ucp
= atmp
->m_apm_data
;
331 while (TRUE
) /* find out how many '00' bytes we can move */
340 memmove(atmp
->m_apm_data
, ucp
, (index
+ 1 - i
));
346 for (i
=0; i
< index
; i
++)
348 M_get_div_rem_10((int)atmp
->m_apm_data
[i
+1], &numdiv
, &numrem2
);
349 atmp
->m_apm_data
[i
] = 10 * numrem
+ numdiv
;
358 while (TRUE
) /* remove trailing '0' if any */
360 index
= ((datalength
+ 1) >> 1) - 1;
362 if ((datalength
& 1) == 0) /* back-up full bytes at a time if the */
363 { /* current length is an even number */
364 ucp
= atmp
->m_apm_data
+ index
;
379 M_get_div_rem_10((int)atmp
->m_apm_data
[index
], &numdiv
, &numrem
);
381 if (numrem
!= 0) /* last digit non-zero, all done */
384 if ((datalength
& 1) != 0) /* if odd, then first char must be non-zero */
392 atmp
->m_apm_sign
= 0;
400 atmp
->m_apm_datalength
= datalength
;
401 atmp
->m_apm_exponent
= exponent
;
403 /****************************************************************************/
404 void M_apm_scale(M_APM ctmp
, int count
)
407 UCHAR
*chp
, numdiv
, numdiv2
, numrem
;
412 ii
= (ctmp
->m_apm_datalength
+ ct
+ 1) >> 1;
413 if (ii
> ctmp
->m_apm_malloclength
)
415 if ((vp
= MAPM_REALLOC(ctmp
->m_apm_data
, (ii
+ 32))) == NULL
)
417 /* fatal, this does not return */
419 M_apm_log_error_msg(M_APM_FATAL
, "\'M_apm_scale\', Out of memory");
422 ctmp
->m_apm_malloclength
= ii
+ 28;
423 ctmp
->m_apm_data
= (UCHAR
*)vp
;
426 if ((ct
& 1) != 0) /* move odd number first */
429 chp
= ctmp
->m_apm_data
;
430 ii
= ((ctmp
->m_apm_datalength
+ 1) >> 1) - 1;
432 if ((ctmp
->m_apm_datalength
& 1) == 0)
435 * original datalength is even:
437 * uv wx yz becomes --> 0u vw xy z0
444 M_get_div_rem_10((int)chp
[ii
], &numdiv2
, &numrem
);
446 chp
[ii
+ 1] = 10 * numrem
+ numdiv
;
460 * original datalength is odd:
462 * uv wx y0 becomes --> 0u vw xy
465 M_get_div_rem_10((int)chp
[ii
], &numdiv2
, &numrem
);
475 M_get_div_rem_10((int)chp
[ii
- 1], &numdiv
, &numrem
);
477 chp
[ii
] = 10 * numrem
+ numdiv2
;
488 ctmp
->m_apm_exponent
++;
489 ctmp
->m_apm_datalength
++;
492 /* ct is even here */
496 numb
= (ctmp
->m_apm_datalength
+ 1) >> 1;
499 memmove((ctmp
->m_apm_data
+ ii
), ctmp
->m_apm_data
, numb
);
500 memset(ctmp
->m_apm_data
, 0, ii
);
502 ctmp
->m_apm_datalength
+= ct
;
503 ctmp
->m_apm_exponent
+= ct
;
506 /****************************************************************************/
507 void M_apm_pad(M_APM ctmp
, int new_length
)
510 UCHAR numdiv
, numrem
;
514 if (ctmp
->m_apm_datalength
>= ct
)
517 numb
= (ct
+ 1) >> 1;
518 if (numb
> ctmp
->m_apm_malloclength
)
520 if ((vp
= MAPM_REALLOC(ctmp
->m_apm_data
, (numb
+ 32))) == NULL
)
522 /* fatal, this does not return */
524 M_apm_log_error_msg(M_APM_FATAL
, "\'M_apm_pad\', Out of memory");
527 ctmp
->m_apm_malloclength
= numb
+ 28;
528 ctmp
->m_apm_data
= (UCHAR
*)vp
;
531 num1
= (ctmp
->m_apm_datalength
+ 1) >> 1;
533 if ((ctmp
->m_apm_datalength
& 1) != 0)
535 M_get_div_rem_10((int)ctmp
->m_apm_data
[num1
- 1], &numdiv
, &numrem
);
536 ctmp
->m_apm_data
[num1
- 1] = 10 * numdiv
;
539 memset((ctmp
->m_apm_data
+ num1
), 0, (numb
- num1
));
540 ctmp
->m_apm_datalength
= ct
;
542 /****************************************************************************/
548 static char buffer[8192];
550 m_apm_to_string(buffer, -1, cc);
551 printf("(dsp func) = [%s]\n",buffer);