00001 #include "multiprec.h"
00002 #include <string.h>
00003
00036 inline size_t
00037 ymp_addabs(digit_t *result, const digit_t *lhs, const digit_t *rhs,
00038 size_t lhs_len, size_t rhs_len)
00039 {
00040 double_digit_t tmp = 0;
00041 size_t i;
00042
00043 for ( i = 0; i < rhs_len; ++i)
00044 {
00045 tmp += lhs[i];
00046 tmp += rhs[i];
00047 result[i] = LOW_DIGIT(tmp);
00048 tmp = HIGH_DIGIT(tmp);
00049 }
00050 for ( ; i < lhs_len; ++i)
00051 {
00052 tmp += lhs[i];
00053 result[i] = LOW_DIGIT(tmp);
00054 tmp = HIGH_DIGIT(tmp);
00055 }
00056 if (LOW_DIGIT(tmp))
00057 {
00058 result[i++] = LOW_DIGIT(tmp);
00059 }
00060 return i;
00061 }
00062
00063
00064
00080 inline size_t
00081 ymp_subabs(digit_t *result, const digit_t *lhs, const digit_t *rhs,
00082 size_t lhs_len, size_t rhs_len)
00083 {
00084 double_digit_t tmp = 1;
00085 size_t i;
00086
00087 for ( i = 0; i < rhs_len; ++i)
00088 {
00089 tmp += MULTIPREC_RADIX - 1;
00090 tmp += lhs[i];
00091 tmp -= rhs[i];
00092 result[i] = LOW_DIGIT(tmp);
00093 tmp = HIGH_DIGIT(tmp);
00094 }
00095 for ( ; i < lhs_len; ++i)
00096 {
00097 tmp += MULTIPREC_RADIX - 1;
00098 tmp += lhs[i];
00099 result[i] = LOW_DIGIT(tmp);
00100 tmp = HIGH_DIGIT(tmp);
00101 }
00102 while (i-- > 0)
00103 {
00104 if (result[i]) break;
00105 }
00106 return ++i;
00107 }
00108
00126 inline static void
00127 ymp_do_add(mp_ref_t result, mp_cref_t self, mp_cref_t other, int is_add)
00128 {
00129 if (self->used > other->used)
00130 {
00131 if (is_add)
00132 {
00133 ymp_reserve(result, self->used+1);
00134 result->used
00135 = ymp_addabs(result->digits, self->digits, other->digits,
00136 self->used, other->used);
00137 result->sign = self->sign;
00138 }
00139 else
00140 {
00141 ymp_reserve(result, self->used);
00142 result->used
00143 = ymp_subabs(result->digits, self->digits, other->digits,
00144 self->used, other->used);
00145 result->sign = self->sign;
00146 }
00147 return;
00148 }
00149 else if (self->used < other->used)
00150 {
00151 if (is_add)
00152 {
00153 ymp_reserve(result, other->used+1);
00154 result->used
00155 = ymp_addabs(result->digits, other->digits, self->digits,
00156 other->used, self->used);
00157 result->sign = self->sign;
00158 }
00159 else
00160 {
00161 ymp_reserve(result, other->used);
00162 result->used
00163 = ymp_subabs(result->digits, other->digits, self->digits,
00164 other->used, self->used);
00165 result->sign = !self->sign;
00166 }
00167 return;
00168 }
00169
00170
00171
00172
00173
00174 if (is_add)
00175 {
00176 ymp_reserve(result, self->used+1);
00177 result->used
00178 = ymp_addabs(result->digits, self->digits, other->digits,
00179 self->used, other->used);
00180 result->sign = self->sign;
00181 }
00182 else
00183 {
00184 size_t i = self->used;
00185 while (i-- > 0)
00186 {
00187 if ( self->digits[i] > other->digits[i])
00188 {
00189 ymp_reserve(result, ++i);
00190 result->used
00191 = ymp_subabs(result->digits, self->digits, other->digits,
00192 i, i);
00193 result->sign = self->sign;
00194 return;
00195 }
00196 else if (self->digits[i] < other->digits[i])
00197 {
00198 ymp_reserve(result, ++i);
00199 result->used
00200 = ymp_subabs(result->digits, other->digits, self->digits,
00201 i, i);
00202 result->sign = !self->sign;
00203 return;
00204 }
00205 }
00206 result->sign = positive_sign;
00207 result->used = 0;
00208 }
00209 }
00210
00211
00212
00227 inline static void
00228 ymp_do_add_digit(mp_ref_t result, mp_cref_t self, digit_t other, int is_add)
00229 {
00230 switch (self->used)
00231 {
00232 case 0:
00233 ymp_reserve(result, 1);
00234 result->sign = self->sign;
00235 result->used = 1;
00236 result->digits[0] = other;
00237 return;
00238
00239 case 1:
00240 if (is_add)
00241 {
00242 double_digit_t tmp;
00243
00244 ymp_reserve(result, 2);
00245 result->sign = self->sign;
00246 result->used = 1;
00247
00248 tmp = other;
00249 tmp += self->digits[0];
00250
00251 result->digits[0] = LOW_DIGIT(tmp);
00252 if ( (tmp = HIGH_DIGIT(tmp)) )
00253 {
00254 self->digits[1] = LOW_DIGIT(tmp);
00255 ++result->used;
00256 }
00257 return;
00258 }
00259 else
00260 {
00261 ymp_reserve(result, 1);
00262 result->used = 1;
00263 if (self->digits[0] > other)
00264 {
00265 result->sign = self->sign;
00266 result->digits[0] = self->digits[0] - other;
00267 }
00268 else
00269 {
00270 result->sign = !self->sign;
00271 self->digits[0] = other - self->digits[0];
00272 }
00273 return;
00274 }
00275 default:
00276 if (is_add)
00277 {
00278 ymp_reserve(result, self->used+1);
00279 result->used
00280 = ymp_addabs(result->digits, self->digits, &other, self->used, 1);
00281 result->sign = self->sign;
00282 return;
00283 }
00284 else
00285 {
00286 ymp_reserve(result, self->used+1);
00287 result->used
00288 = ymp_subabs(result->digits, self->digits, &other, self->used, 1);
00289 result->sign = self->sign;
00290 return;
00291 }
00292 }
00293 }
00294
00295
00296
00297
00298
00309 void ymp_add(mp_ref_t result, mp_cref_t self, mp_cref_t other)
00310 {
00311 ymp_do_add(result, self, other, self->sign==other->sign);
00312 }
00313
00324 void ymp_sub(mp_ref_t result, mp_cref_t self, mp_cref_t other)
00325 {
00326 ymp_do_add(result, self, other, self->sign!=other->sign);
00327 }
00328
00329
00330
00338 void
00339 ymp_add_digit(mp_ref_t result, mp_cref_t self, digit_t val)
00340 {
00341 ymp_do_add_digit(result, self, val, self->sign==positive_sign);
00342 }
00343
00351 void
00352 ymp_sub_digit(mp_ref_t result, mp_cref_t self, digit_t val)
00353 {
00354 ymp_do_add_digit(result, self, val, self->sign!=positive_sign);
00355 }
00356
00357
00366 void ymp_neg(mp_ref_t result, mp_cref_t orig)
00367 {
00368 result->sign = !orig->sign;
00369 if (result != orig)
00370 {
00371 ymp_reserve(result, orig->used);
00372 result->used = orig->used;
00373 memcpy(result->digits, orig->digits, sizeof(digit_t)*orig->used);
00374 }
00375 }
00376