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.
23
* This file contains the basic division functions
28
#include "pgscript/utilities/mapm-lib/m_apm_lc.h"
30
static M_APM M_div_worka;
31
static M_APM M_div_workb;
32
static M_APM M_div_tmp7;
33
static M_APM M_div_tmp8;
34
static M_APM M_div_tmp9;
36
static int M_div_firsttime = TRUE;
38
/****************************************************************************/
41
if (M_div_firsttime == FALSE)
43
m_apm_free(M_div_worka);
44
m_apm_free(M_div_workb);
45
m_apm_free(M_div_tmp7);
46
m_apm_free(M_div_tmp8);
47
m_apm_free(M_div_tmp9);
49
M_div_firsttime = TRUE;
52
/****************************************************************************/
53
void m_apm_integer_div_rem(M_APM qq, M_APM rr, M_APM aa, M_APM bb)
55
m_apm_integer_divide(qq, aa, bb);
56
m_apm_multiply(M_div_tmp7, qq, bb);
57
m_apm_subtract(rr, aa, M_div_tmp7);
59
/****************************************************************************/
60
void m_apm_integer_divide(M_APM rr, M_APM aa, M_APM bb)
63
* we must use this divide function since the
64
* faster divide function using the reciprocal
65
* will round the result (possibly changing
66
* nnm.999999... --> nn(m+1).0000 which would
67
* invalidate the 'integer_divide' goal).
70
M_apm_sdivide(rr, 4, aa, bb);
72
if (rr->m_apm_exponent <= 0) /* result is 0 */
78
if (rr->m_apm_datalength > rr->m_apm_exponent)
80
rr->m_apm_datalength = rr->m_apm_exponent;
85
/****************************************************************************/
86
void M_apm_sdivide(M_APM r, int places, M_APM a, M_APM b)
88
int j, k, m, b0, sign, nexp, indexr, icompare, iterations;
94
M_div_firsttime = FALSE;
96
M_div_worka = m_apm_init();
97
M_div_workb = m_apm_init();
98
M_div_tmp7 = m_apm_init();
99
M_div_tmp8 = m_apm_init();
100
M_div_tmp9 = m_apm_init();
103
sign = a->m_apm_sign * b->m_apm_sign;
105
if (sign == 0) /* one number is zero, result is zero */
107
if (b->m_apm_sign == 0)
109
M_apm_log_error_msg(M_APM_RETURN, "\'M_apm_sdivide\', Divide by 0");
117
* Knuth step D1. Since base = 100, base / 2 = 50.
118
* (also make the working copies positive)
121
if (b->m_apm_data[0] >= 50)
123
m_apm_absolute_value(M_div_worka, a);
124
m_apm_absolute_value(M_div_workb, b);
126
else /* 'normal' step D1 */
128
k = 100 / (b->m_apm_data[0] + 1);
129
m_apm_set_long(M_div_tmp9, (long)k);
131
m_apm_multiply(M_div_worka, M_div_tmp9, a);
132
m_apm_multiply(M_div_workb, M_div_tmp9, b);
134
M_div_worka->m_apm_sign = 1;
135
M_div_workb->m_apm_sign = 1;
138
/* setup trial denominator for step D3 */
140
b0 = 100 * (int)M_div_workb->m_apm_data[0];
142
if (M_div_workb->m_apm_datalength >= 3)
143
b0 += M_div_workb->m_apm_data[1];
145
nexp = M_div_worka->m_apm_exponent - M_div_workb->m_apm_exponent;
148
iterations = nexp + places + 1;
150
iterations = places + 1;
152
k = (iterations + 1) >> 1; /* required size of result, in bytes */
154
if (k > r->m_apm_malloclength)
156
if ((vp = MAPM_REALLOC(r->m_apm_data, (k + 32))) == NULL)
158
/* fatal, this does not return */
160
M_apm_log_error_msg(M_APM_FATAL, "\'M_apm_sdivide\', Out of memory");
163
r->m_apm_malloclength = k + 28;
164
r->m_apm_data = (UCHAR *)vp;
167
/* clear the exponent in the working copies */
169
M_div_worka->m_apm_exponent = 0;
170
M_div_workb->m_apm_exponent = 0;
172
/* if numbers are equal, ratio == 1.00000... */
174
if ((icompare = m_apm_compare(M_div_worka, M_div_workb)) == 0)
177
r->m_apm_data[0] = 10;
180
else /* ratio not 1, do the real division */
182
if (icompare == 1) /* numerator > denominator */
184
nexp++; /* to adjust the final exponent */
185
M_div_worka->m_apm_exponent += 1; /* multiply numerator by 10 */
187
else /* numerator < denominator */
189
M_div_worka->m_apm_exponent += 2; /* multiply numerator by 100 */
198
* Knuth step D3. Only use the 3rd -> 6th digits if the number
199
* actually has that many digits.
202
trial_numer = 10000L * (long)M_div_worka->m_apm_data[0];
204
if (M_div_worka->m_apm_datalength >= 5)
206
trial_numer += 100 * M_div_worka->m_apm_data[1]
207
+ M_div_worka->m_apm_data[2];
211
if (M_div_worka->m_apm_datalength >= 3)
212
trial_numer += 100 * M_div_worka->m_apm_data[1];
215
j = (int)(trial_numer / b0);
218
* Since the library 'normalizes' all the results, we need
219
* to look at the exponent of the number to decide if we
220
* have a lead in 0n or 00.
223
if ((k = 2 - M_div_worka->m_apm_exponent) > 0)
233
if (j == 100) /* qhat == base ?? */
234
j = 99; /* if so, decrease by 1 */
236
m_apm_set_long(M_div_tmp8, (long)j);
237
m_apm_multiply(M_div_tmp7, M_div_tmp8, M_div_workb);
240
* Compare our q-hat (j) against the desired number.
241
* j is either correct, 1 too large, or 2 too large
242
* per Theorem B on pg 272 of Art of Compter Programming,
243
* Volume 2, 3rd Edition.
245
* The above statement is only true if using the 2 leading
246
* digits of the numerator and the leading digit of the
247
* denominator. Since we are using the (3) leading digits
248
* of the numerator and the (2) leading digits of the
249
* denominator, we eliminate the case where our q-hat is
250
* 2 too large, (and q-hat being 1 too large is quite remote).
253
if (m_apm_compare(M_div_tmp7, M_div_worka) == 1)
256
m_apm_subtract(M_div_tmp8, M_div_tmp7, M_div_workb);
257
m_apm_copy(M_div_tmp7, M_div_tmp8);
261
* Since we know q-hat is correct, step D6 is unnecessary.
263
* Store q-hat, step D5. Since D6 is unnecessary, we can
264
* do D5 before D4 and decide if we are done.
267
r->m_apm_data[indexr++] = (UCHAR)j; /* j == 'qhat' */
275
m_apm_subtract(M_div_tmp9, M_div_worka, M_div_tmp7);
278
* if the subtraction yields zero, the division is exact
279
* and we are done early.
282
if (M_div_tmp9->m_apm_sign == 0)
288
/* multiply by 100 and re-save */
289
M_div_tmp9->m_apm_exponent += 2;
290
m_apm_copy(M_div_worka, M_div_tmp9);
294
r->m_apm_sign = sign;
295
r->m_apm_exponent = nexp;
296
r->m_apm_datalength = iterations;
300
/****************************************************************************/