0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #include "mpi-internal.h"
0015 #include "longlong.h"
0016
0017 void mpi_tdiv_qr(MPI quot, MPI rem, MPI num, MPI den);
0018 void mpi_fdiv_qr(MPI quot, MPI rem, MPI dividend, MPI divisor);
0019
0020 void mpi_fdiv_r(MPI rem, MPI dividend, MPI divisor)
0021 {
0022 int divisor_sign = divisor->sign;
0023 MPI temp_divisor = NULL;
0024
0025
0026
0027
0028
0029 if (rem == divisor) {
0030 temp_divisor = mpi_copy(divisor);
0031 divisor = temp_divisor;
0032 }
0033
0034 mpi_tdiv_r(rem, dividend, divisor);
0035
0036 if (((divisor_sign?1:0) ^ (dividend->sign?1:0)) && rem->nlimbs)
0037 mpi_add(rem, rem, divisor);
0038
0039 if (temp_divisor)
0040 mpi_free(temp_divisor);
0041 }
0042
0043 void mpi_fdiv_q(MPI quot, MPI dividend, MPI divisor)
0044 {
0045 MPI tmp = mpi_alloc(mpi_get_nlimbs(quot));
0046 mpi_fdiv_qr(quot, tmp, dividend, divisor);
0047 mpi_free(tmp);
0048 }
0049
0050 void mpi_fdiv_qr(MPI quot, MPI rem, MPI dividend, MPI divisor)
0051 {
0052 int divisor_sign = divisor->sign;
0053 MPI temp_divisor = NULL;
0054
0055 if (quot == divisor || rem == divisor) {
0056 temp_divisor = mpi_copy(divisor);
0057 divisor = temp_divisor;
0058 }
0059
0060 mpi_tdiv_qr(quot, rem, dividend, divisor);
0061
0062 if ((divisor_sign ^ dividend->sign) && rem->nlimbs) {
0063 mpi_sub_ui(quot, quot, 1);
0064 mpi_add(rem, rem, divisor);
0065 }
0066
0067 if (temp_divisor)
0068 mpi_free(temp_divisor);
0069 }
0070
0071
0072
0073
0074
0075
0076
0077
0078 void mpi_tdiv_r(MPI rem, MPI num, MPI den)
0079 {
0080 mpi_tdiv_qr(NULL, rem, num, den);
0081 }
0082
0083 void mpi_tdiv_qr(MPI quot, MPI rem, MPI num, MPI den)
0084 {
0085 mpi_ptr_t np, dp;
0086 mpi_ptr_t qp, rp;
0087 mpi_size_t nsize = num->nlimbs;
0088 mpi_size_t dsize = den->nlimbs;
0089 mpi_size_t qsize, rsize;
0090 mpi_size_t sign_remainder = num->sign;
0091 mpi_size_t sign_quotient = num->sign ^ den->sign;
0092 unsigned int normalization_steps;
0093 mpi_limb_t q_limb;
0094 mpi_ptr_t marker[5];
0095 int markidx = 0;
0096
0097
0098
0099
0100
0101 rsize = nsize + 1;
0102 mpi_resize(rem, rsize);
0103
0104 qsize = rsize - dsize;
0105 if (qsize <= 0) {
0106 if (num != rem) {
0107 rem->nlimbs = num->nlimbs;
0108 rem->sign = num->sign;
0109 MPN_COPY(rem->d, num->d, nsize);
0110 }
0111 if (quot) {
0112
0113
0114
0115 quot->nlimbs = 0;
0116 quot->sign = 0;
0117 }
0118 return;
0119 }
0120
0121 if (quot)
0122 mpi_resize(quot, qsize);
0123
0124
0125 np = num->d;
0126 dp = den->d;
0127 rp = rem->d;
0128
0129
0130 if (dsize == 1) {
0131 mpi_limb_t rlimb;
0132 if (quot) {
0133 qp = quot->d;
0134 rlimb = mpihelp_divmod_1(qp, np, nsize, dp[0]);
0135 qsize -= qp[qsize - 1] == 0;
0136 quot->nlimbs = qsize;
0137 quot->sign = sign_quotient;
0138 } else
0139 rlimb = mpihelp_mod_1(np, nsize, dp[0]);
0140 rp[0] = rlimb;
0141 rsize = rlimb != 0?1:0;
0142 rem->nlimbs = rsize;
0143 rem->sign = sign_remainder;
0144 return;
0145 }
0146
0147
0148 if (quot) {
0149 qp = quot->d;
0150
0151
0152
0153 if (qp == np) {
0154 np = marker[markidx++] = mpi_alloc_limb_space(nsize);
0155 MPN_COPY(np, qp, nsize);
0156 }
0157 } else
0158 qp = rp + dsize;
0159
0160 normalization_steps = count_leading_zeros(dp[dsize - 1]);
0161
0162
0163
0164
0165
0166 if (normalization_steps) {
0167 mpi_ptr_t tp;
0168 mpi_limb_t nlimb;
0169
0170
0171
0172
0173
0174 tp = marker[markidx++] = mpi_alloc_limb_space(dsize);
0175 mpihelp_lshift(tp, dp, dsize, normalization_steps);
0176 dp = tp;
0177
0178
0179
0180
0181
0182 nlimb = mpihelp_lshift(rp, np, nsize, normalization_steps);
0183 if (nlimb) {
0184 rp[nsize] = nlimb;
0185 rsize = nsize + 1;
0186 } else
0187 rsize = nsize;
0188 } else {
0189
0190
0191
0192 if (dp == rp || (quot && (dp == qp))) {
0193 mpi_ptr_t tp;
0194
0195 tp = marker[markidx++] = mpi_alloc_limb_space(dsize);
0196 MPN_COPY(tp, dp, dsize);
0197 dp = tp;
0198 }
0199
0200
0201 if (rp != np)
0202 MPN_COPY(rp, np, nsize);
0203
0204 rsize = nsize;
0205 }
0206
0207 q_limb = mpihelp_divrem(qp, 0, rp, rsize, dp, dsize);
0208
0209 if (quot) {
0210 qsize = rsize - dsize;
0211 if (q_limb) {
0212 qp[qsize] = q_limb;
0213 qsize += 1;
0214 }
0215
0216 quot->nlimbs = qsize;
0217 quot->sign = sign_quotient;
0218 }
0219
0220 rsize = dsize;
0221 MPN_NORMALIZE(rp, rsize);
0222
0223 if (normalization_steps && rsize) {
0224 mpihelp_rshift(rp, rp, rsize, normalization_steps);
0225 rsize -= rp[rsize - 1] == 0?1:0;
0226 }
0227
0228 rem->nlimbs = rsize;
0229 rem->sign = sign_remainder;
0230 while (markidx) {
0231 markidx--;
0232 mpi_free_limb_space(marker[markidx]);
0233 }
0234 }