モジュール | |
下位関数群 | |
マクロ定義 | |
#define | ymp_div(quotient, self, other) ymp_divmod((quotient), NULL, (self), (other)) |
多倍長整数の整除. より詳しく... | |
#define | ymp_mod(remainder, self, other) ymp_divmod(NULL, (remainder), (self), (other)) |
多倍長整数の剰余計算. より詳しく... | |
#define | ymp_div_digit(quotient, self, other) (void)ymp_divmod_digit((quotient), (self), (other)) |
多倍長整数のdigit_tによる整除. より詳しく... | |
#define | ymp_mod_digit(self, other) ymp_divmod_digit(NULL, (self), (other)) |
多倍長整数のdigit_tによる剰余計算. より詳しく... | |
#define | ymp_is_divisible(self, other) ymp_div_if_divisible(NULL, (self), (other)) |
多倍長整数が割り切れるかを判定. より詳しく... | |
#define | ymp_is_divisible_digit(self, other) ymp_div_if_divisible_digit(NULL, (self), (other)) |
多倍長整数がdigit_tで割り切れるかを判定. より詳しく... | |
関数 | |
void | ymp_do_add (mp_ref_t result, mp_cref_t self, mp_cref_t other, int is_add) |
加減算を実行する。. より詳しく... | |
void | ymp_do_add_digit (mp_ref_t result, mp_cref_t self, digit_t other, int is_add) |
digit_tとの加減算を実行する。. より詳しく... | |
void | ymp_add (mp_ref_t result, mp_cref_t self, mp_cref_t other) |
多倍長整数の加算. より詳しく... | |
void | ymp_sub (mp_ref_t result, mp_cref_t self, mp_cref_t other) |
多倍長整数の減算. より詳しく... | |
void | ymp_add_digit (mp_ref_t result, mp_cref_t self, digit_t val) |
多倍長整数にdigit_tを足す. より詳しく... | |
void | ymp_sub_digit (mp_ref_t result, mp_cref_t self, digit_t val) |
多倍長整数からdigit_tを引く. より詳しく... | |
void | ymp_neg (mp_ref_t result, mp_cref_t orig) |
多倍長整数の符号反転. より詳しく... | |
void | ymp_divmod (mp_ref_t quotient, mp_ref_t remainder, mp_cref_t self, mp_cref_t other) |
多倍長整数の除算. より詳しく... | |
digit_t | ymp_divmod_digit (mp_ref_t quotient, mp_cref_t self, digit_t other) |
多倍長整数の、digit_tによる除算. より詳しく... | |
int | ymp_div_if_divisible (mp_ref_t quotient, mp_cref_t self, mp_cref_t other) |
多倍長整数を、もし可能なら割る. より詳しく... | |
int | ymp_div_if_divisible_digit (mp_ref_t quotient, mp_cref_t self, digit_t other) |
多倍長整数をdigit_tで、もし可能なら割る. より詳しく... | |
void | ymp_mul (mp_ref_t result, mp_cref_t self, mp_cref_t other) |
多倍長整数同士を掛ける. より詳しく... | |
void | ymp_modmul (mp_ref_t result, mp_cref_t self, mp_cref_t other, mp_cref_t modulus) |
多倍長整数の積の剰余を求める. より詳しく... | |
void | ymp_modmul_2exp (mp_ref_t result, mp_cref_t self, mp_cref_t other, size_t pow) |
多倍長自然数の積の、2の冪による剰余を求める. より詳しく... | |
void | ymp_mul_digit (mp_ref_t result, mp_cref_t self, digit_t other) |
多倍長整数にdigit_tを掛ける. より詳しく... | |
void | ymp_pow (mp_ref_t result, mp_cref_t self, size_t pow) |
多倍長整数の冪 (冪指数はsize_t). より詳しく... | |
void | ymp_modpow_z (mp_ref_t result, mp_cref_t self, mp_cref_t modulus, size_t pow) |
多倍長整数の冪の剰余を求める(冪指数はsize_t). より詳しく... | |
void | ymp_modpow_2exp_z (mp_ref_t result, mp_cref_t self, size_t emod, size_t pow) |
多倍長整数の冪の、2の冪による剰余を求める(冪指数はsize_t). より詳しく... | |
void | ymp_modpow (mp_ref_t result, mp_cref_t self, mp_cref_t modulus, mp_cref_t pow) |
多倍長整数の冪の剰余を求める(冪指数は多倍長). より詳しく... | |
void | ymp_mul_2exp (mp_ref_t result, mp_cref_t self, size_t pow) |
多倍長整数を2の冪乗倍する. より詳しく... | |
void | ymp_div_2exp (mp_ref_t result, mp_cref_t self, size_t pow) |
多倍長整数を2の冪乗で割る. より詳しく... | |
void | ymp_mod_2exp (mp_ref_t result, mp_cref_t self, size_t pow) |
多倍長整数を2の冪乗で割った剰余. より詳しく... | |
void | ymp_iroot (mp_ref_t result, mp_cref_t self, size_t pow) |
多倍長整数の冪乗根の整数部分. より詳しく... |
|
多倍長整数の整除.
multiprec.h の 458 行で定義されています。 呼出 ymp_iroot. |
|
多倍長整数の剰余計算.
multiprec.h の 470 行で定義されています。 呼出 ymp_binary_sunzi, と ymp_modinv. |
|
多倍長整数のdigit_tによる整除.
multiprec.h の 482 行で定義されています。 |
|
多倍長整数のdigit_tによる剰余計算.
multiprec.h の 494 行で定義されています。 |
|
多倍長整数が割り切れるかを判定.
multiprec.h の 512 行で定義されています。 |
|
多倍長整数がdigit_tで割り切れるかを判定.
multiprec.h の 524 行で定義されています。 |
|
加減算を実行する。.
参照 multiprec::digits, mp_cref_t, positive_sign, multiprec::sign, multiprec::used, ymp_addabs, ymp_reserve, と ymp_subabs.
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 /* self->used == other->used */ 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 } |
|
digit_tとの加減算を実行する。.
参照 digit_t, multiprec::digits, double_digit_t, HIGH_DIGIT, LOW_DIGIT, mp_cref_t, multiprec::sign, multiprec::used, ymp_addabs, ymp_reserve, と ymp_subabs. 呼出 ymp_add_digit, と ymp_sub_digit.
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 } |
|
多倍長整数の加算. <result>に<self> + <other>を格納する
参照 mp_cref_t, multiprec::sign, と ymp_do_add.
00310 { 00311 ymp_do_add(result, self, other, self->sign==other->sign); 00312 } |
|
多倍長整数の減算. <result>に<self> - <other>を格納する
参照 mp_cref_t, multiprec::sign, と ymp_do_add.
00325 { 00326 ymp_do_add(result, self, other, self->sign!=other->sign); 00327 } |
|
多倍長整数にdigit_tを足す.
参照 digit_t, mp_cref_t, positive_sign, multiprec::sign, と ymp_do_add_digit.
00340 { 00341 ymp_do_add_digit(result, self, val, self->sign==positive_sign); 00342 } |
|
多倍長整数からdigit_tを引く.
参照 digit_t, mp_cref_t, positive_sign, multiprec::sign, と ymp_do_add_digit.
00353 { 00354 ymp_do_add_digit(result, self, val, self->sign!=positive_sign); 00355 } |
|
多倍長整数の符号反転. <result> := -<self>
参照 digit_t, multiprec::digits, mp_cref_t, multiprec::sign, multiprec::used, と ymp_reserve.
|
|
多倍長整数の除算.
参照 multiprec::digits, mp_cref_t, mp_sign_t, multiprec::sign, multiprec::used, ymp_assign, ymp_divmodabs, ymp_fatal, ymp_is_zero, と ymp_reserve.
00264 { 00265 enum mp_sign_t rem_sign; 00266 size_t rem_used; 00267 00268 /* 0除算を弾く */ 00269 if (ymp_is_zero(other)) 00270 { 00271 ymp_fatal("0による除算"); 00272 return; 00273 } 00274 00275 /* 明らかに (被除数) < (除数) と分かる場合: 00276 商は0、剰余は被除数に等しい */ 00277 if (self->used < other->used) 00278 { 00279 if (quotient) quotient->used = 0; 00280 if (self != remainder && remainder) ymp_assign(remainder, self); 00281 return; 00282 } 00283 00284 /* 商・剰余の格納に十分な領域を確保 */ 00285 if (quotient) ymp_reserve(quotient, self->used-other->used+1); 00286 if (remainder) ymp_reserve(remainder, other->used); 00287 00288 /* 絶対値同士の除算を行う */ 00289 rem_sign = self->sign; 00290 rem_used = ymp_divmodabs(quotient?quotient->digits:NULL, 00291 remainder?remainder->digits:NULL, 00292 self->digits, other->digits, 00293 self->used, other->used); 00294 00295 /* 00296 * remainder==selfまたはremainder==otherのときにも 00297 * 商のの符号と桁数の調整に影響を与えないように、 00298 * 剰余の符号と桁数は直ぐには書き込まない 00299 */ 00300 00301 if (quotient) 00302 { 00303 /* 商の符号と桁数の調整 */ 00304 quotient->sign = self->sign != other->sign; 00305 quotient->used = self->used - other->used + 1; 00306 if (!quotient->digits[quotient->used-1]) --quotient->used; 00307 } 00308 00309 if (remainder) 00310 { 00311 /* 剰余の符号と桁数を書き込む */ 00312 remainder->sign = rem_sign; 00313 remainder->used = rem_used; 00314 } 00315 } |
|
多倍長整数の、digit_tによる除算.
参照 digit_t, multiprec::digits, multiprec::len, mp_cref_t, multiprec::sign, multiprec::used, ymp_addabs, ymp_divmodabs_digit, ymp_fatal, と ymp_reserve.
00334 { 00335 digit_t rem; /* 剰余の絶対値 */ 00336 00337 /* 0除算を弾く */ 00338 if (other == 0) 00339 { 00340 ymp_fatal("0による除算"); 00341 return 0; 00342 } 00343 00344 /* 被除数が0の場合、商と剰余も0 */ 00345 if (self->used == 0) 00346 { 00347 if (quotient) quotient->used = 0; 00348 return 0; 00349 } 00350 00351 /* 商を格納するのに十分な領域を確保 */ 00352 if (quotient) ymp_reserve(quotient, self->used); 00353 00354 /* 絶対値の除算を行う */ 00355 rem = ymp_divmodabs_digit(quotient?quotient->digits:NULL, 00356 self->digits, 00357 other, 00358 self->used); 00359 00360 /* 桁数と符号の設定 */ 00361 if (quotient) 00362 { 00363 if (quotient->digits[quotient->used-1]) --quotient->used; 00364 quotient->sign = self->sign; 00365 } 00366 00367 if (self->sign && rem) 00368 { 00369 /* 剰余が正になるように調整 */ 00370 if (quotient) 00371 { 00372 quotient->used = ymp_addabs(quotient->digits, quotient->digits, 00373 &other, quotient->len, 1); 00374 } 00375 return other - rem; 00376 } 00377 else 00378 { 00379 return rem; 00380 } 00381 } |
|
多倍長整数を、もし可能なら割る. selfがotherで割れるかどうか調べ、もし割り切れるなら商をquotientに代入する 割り切れないときはquotientは変化しない
参照 digit_t, multiprec::digits, mp_cref_t, multiprec::sign, multiprec::used, ymp_divmodabs, ymp_fatal, ymp_is_zero, ymp_reserve, と YMP_TEMP_ALLOCATE.
00400 { 00401 size_t rem_used; /* 剰余の桁数 */ 00402 digit_t *quot_buf=NULL, *rem_buf=NULL; /* 商・剰余の一時格納用 */ 00403 00404 /* 0除算を弾く */ 00405 if (ymp_is_zero(other)) 00406 { 00407 ymp_fatal("0による除算"); 00408 return 2; 00409 } 00410 00411 /* 明らかな場合 */ 00412 if (self->used < other->used) 00413 { 00414 if (ymp_is_zero(self)) 00415 { 00416 if (quotient) quotient->used = 0; 00417 return 1; 00418 } 00419 else 00420 { 00421 return 0; 00422 } 00423 } 00424 00425 /* 格納領域を確保 */ 00426 if (quotient) YMP_TEMP_ALLOCATE(quot_buf, digit_t, self->used-other->used+1); 00427 YMP_TEMP_ALLOCATE(rem_buf, digit_t, other->used); 00428 00429 /* 絶対値の除算を実行 */ 00430 rem_used = ymp_divmodabs(quot_buf, rem_buf, self->digits, other->digits, 00431 self->used, other->used); 00432 00433 /* 剰余が0なら (そのときrem_usedは必ず0) */ 00434 if (rem_used==0) 00435 { 00436 if (quotient) 00437 { 00438 /* *quotientに商のデータをコピー */ 00439 size_t quot_used; 00440 quotient->sign = self->sign != other->sign; 00441 00442 quot_used = self->used - other->used + 1; 00443 if (!quot_buf[quot_used-1]) --quot_used; 00444 quotient->used = quot_used; 00445 ymp_reserve(quotient, quot_used); 00446 memcpy(quotient->digits, quot_buf, quot_used); 00447 } 00448 return 1; 00449 } 00450 else 00451 { 00452 return 0; 00453 } 00454 } |
|
多倍長整数をdigit_tで、もし可能なら割る. selfがotherで割れるかどうか調べ、もし割り切れるなら商をquotientに代入する 割り切れないときはquotientは変化しない
参照 digit_t, multiprec::digits, mp_cref_t, multiprec::sign, multiprec::used, ymp_divmodabs_digit, ymp_fatal, ymp_is_zero, ymp_reserve, と YMP_TEMP_ALLOCATE.
00475 { 00476 digit_t rem; 00477 digit_t *quot_buf=NULL; 00478 00479 /* 0除算を弾く */ 00480 if (other == 0) 00481 { 00482 ymp_fatal("0による除算"); 00483 return 2; 00484 } 00485 00486 /* 明らかな場合 */ 00487 if (ymp_is_zero(self)) 00488 { 00489 if (quotient) quotient->used = 0; 00490 return 1; 00491 } 00492 00493 /* 格納領域を確保 */ 00494 if (quotient) YMP_TEMP_ALLOCATE(quot_buf, digit_t, self->used); 00495 00496 /* 絶対値の除算を実行 */ 00497 rem = ymp_divmodabs_digit(quot_buf, self->digits, other, self->used); 00498 00499 /* 剰余が0なら */ 00500 if (rem == 0) 00501 { 00502 if (quotient) 00503 { 00504 /* *quotientに商のデータをコピー */ 00505 size_t quot_used; 00506 quotient->sign = self->sign; 00507 00508 quot_used = self->used; 00509 if (!quot_buf[quot_used-1]) --quot_used; 00510 quotient->used = quot_used; 00511 ymp_reserve(quotient, quot_used); 00512 memcpy(quotient->digits, quot_buf, quot_used); 00513 } 00514 return 1; 00515 } 00516 else 00517 { 00518 return 0; 00519 } 00520 } |
|
多倍長整数同士を掛ける.
参照 digit_t, multiprec::digits, mp_cref_t, multiprec::sign, multiprec::used, ymp_mulabs, ymp_reserve, と YMP_TEMP_ALLOCATE.
00238 { 00239 digit_t *self_digits = self->digits; 00240 digit_t *other_digits = other->digits; 00241 if (result == self) 00242 { 00243 YMP_TEMP_ALLOCATE(self_digits, digit_t, self->used); 00244 memcpy(self_digits, self->digits, sizeof(digit_t)*self->used); 00245 } 00246 if (result == other) 00247 { 00248 YMP_TEMP_ALLOCATE(other_digits, digit_t, self->used); 00249 memcpy(other_digits, other->digits, sizeof(digit_t)*self->used); 00250 } 00251 00252 ymp_reserve(result, self->used+other->used); 00253 result->used = ymp_mulabs(result->digits, self_digits, other_digits, 00254 self->used, other->used); 00255 00256 result->sign = self->sign != other->sign; 00257 } |
|
多倍長整数の積の剰余を求める. <result> := <self> * <other> % <modulus>
参照 digit_t, multiprec::digits, mp_cref_t, multiprec::sign, multiprec::used, ymp_modmulabs, ymp_reserve, と YMP_TEMP_ALLOCATE.
00276 { 00277 digit_t *self_digits = self->digits; 00278 digit_t *other_digits = other->digits; 00279 00280 if (result == self) 00281 { 00282 YMP_TEMP_ALLOCATE(self_digits, digit_t, self->used); 00283 memcpy(self_digits, self->digits, sizeof(digit_t)*self->used); 00284 } 00285 if (result == other) 00286 { 00287 YMP_TEMP_ALLOCATE(other_digits, digit_t, self->used); 00288 memcpy(other_digits, other->digits, sizeof(digit_t)*self->used); 00289 } 00290 00291 ymp_reserve(result, modulus->used); 00292 00293 result->used = ymp_modmulabs(result->digits, 00294 self_digits, other->digits, modulus->digits, 00295 self->used, other->used, modulus->used); 00296 00297 result->sign = self->sign != other->sign; 00298 } |
|
多倍長自然数の積の、2の冪による剰余を求める. <result> := <self> * <other> % (2**pow)
参照 DIGIT_BIT, multiprec::digits, mp_cref_t, multiprec::sign, multiprec::used, ymp_modmulabs_2exp, と ymp_reserve.
00316 { 00317 ymp_reserve(result, pow/DIGIT_BIT + 1); 00318 00319 result->used = ymp_modmulabs_2exp(result->digits, 00320 self->digits, other->digits, 00321 pow, self->used, other->used); 00322 00323 result->sign = self->sign != other->sign; 00324 } |
|
多倍長整数にdigit_tを掛ける.
参照 digit_t, multiprec::digits, mp_cref_t, multiprec::sign, multiprec::used, ymp_mulabs_digit, と ymp_reserve.
00338 { 00339 ymp_reserve(result, self->used+1); 00340 result->used = ymp_mulabs_digit(result->digits, 00341 self->digits, other, self->used); 00342 result->sign = self->sign; 00343 } |
|
多倍長整数の冪 (冪指数はsize_t). <result> := <self>**<pow>
参照 multiprec::digits, MAX, mp_cref_t, multiprec::sign, multiprec::used, ymp_powabs, と ymp_reserve.
00648 { 00649 /* 結果の格納領域を確保 */ 00650 ymp_reserve(result, self->used*MAX(pow, 1)); 00651 00652 result->sign = self->sign && (pow & 0x01); 00653 result->used = ymp_powabs(result->digits, self->digits, self->used, pow); 00654 } |
|
多倍長整数の冪の剰余を求める(冪指数はsize_t). <result> := <self>**<pow> % <modulus>
参照 multiprec::digits, mp_cref_t, multiprec::sign, multiprec::used, ymp_modpowabs_z, と ymp_reserve.
00671 { 00672 /* 十分な格納領域を確保 */ 00673 ymp_reserve(result, modulus->used); 00674 00675 result->sign = self->sign && (pow & 0x01); 00676 result->used = ymp_modpowabs_z(result->digits, self->digits, modulus->digits, 00677 self->used, modulus->used, pow); 00678 } |
|
多倍長整数の冪の、2の冪による剰余を求める(冪指数はsize_t). <result> := <self>**<pow> % (2**emod)
参照 DIGIT_BIT, multiprec::digits, mp_cref_t, multiprec::sign, multiprec::used, ymp_modpowabs_2exp_z, と ymp_reserve.
00696 { 00697 /* 十分な格納領域を確保 */ 00698 ymp_reserve(result, emod / DIGIT_BIT + 1); 00699 00700 result->sign = self->sign && (pow & 0x01); 00701 result->used = ymp_modpowabs_2exp_z(result->digits, self->digits, 00702 self->used, emod, pow); 00703 } |
|
多倍長整数の冪の剰余を求める(冪指数は多倍長). <result> := <self>**<pow> % <modulus>
参照 multiprec::digits, mp_cref_t, multiprec::sign, multiprec::used, ymp_modpowabs, と ymp_reserve.
00719 { 00720 /* 十分な格納領域を確保 */ 00721 ymp_reserve(result, modulus->used); 00722 00723 result->sign = self->sign && (pow->used != 0 || (pow->digits[0] & 0x01)); 00724 result->used = ymp_modpowabs(result->digits, 00725 self->digits, modulus->digits, pow->digits, 00726 self->used, modulus->used, pow->used); 00727 } |
|
多倍長整数を2の冪乗倍する. <self>に2のpow乗を掛けた積をresultに格納する。
00170 { 00171 result->sign = self->sign; 00172 ymp_reserve(result, self->used+pow/DIGIT_BIT+1); 00173 result->used = ymp_lshiftabs(result->digits, self->digits, self->used, pow); 00174 } |
|
多倍長整数を2の冪乗で割る. <self>を2のpow乗で割った商をresultに格納する。
00190 { 00191 size_t n_shift_digits = pow/DIGIT_BIT; 00192 00193 if (self->used > n_shift_digits) 00194 { 00195 result->sign = self->sign; 00196 ymp_reserve(result, self->used - n_shift_digits); 00197 result->used 00198 = ymp_rshiftabs(result->digits, self->digits, self->used, pow); 00199 } 00200 else 00201 { 00202 result->used = 0; 00203 } 00204 } |
|
多倍長整数を2の冪乗で割った剰余. <self>を2のpow乗で割った剰余をresultに格納する。
00218 { 00219 size_t n_digits = pow / DIGIT_BIT; 00220 ymp_reserve(result, n_digits>self->used ? self->used : n_digits); 00221 result->sign = self->sign; 00222 result->used = ymp_modabs_2exp(result->digits, self->digits, self->used, pow); 00223 } |
|
多倍長整数の冪乗根の整数部分. result := floor( <self> ** (1/n) )
00017 { 00018 /* Newton法による */ 00019 00020 size_t i; 00021 size_t ilog2, bit_len; 00022 struct multiprec x, x_prev; /* 近似途中の値を保持 */ 00023 struct multiprec tmp; /* 計算上の一時領域 */ 00024 struct multiprec self_copy; 00025 00026 if (!self->sign) 00027 { /* 非負ならば良い */ 00028 result->sign = positive_sign; 00029 } 00030 else 00031 { /* そうでないとき */ 00032 /* 偶数乗根はエラー */ 00033 if ( (n & 0x01) == 0) ymp_fatal("負数の偶数乗根"); 00034 00035 /* 結果の符号が確定 */ 00036 result->sign = self->sign; 00037 00038 /* 以下、-<self> >= 0 の絶対値を算出すれば良い */ 00039 memcpy(&self_copy, self, sizeof(struct multiprec)); 00040 self_copy.sign = positive_sign; 00041 self = &self_copy; 00042 } 00043 00044 /* bit長により、初期値を大まかに決定 */ 00045 /* (初期値) >= (収束値) を保証して収束が遅くなるのを防止する */ 00046 /* ilog2 := { 2**k > |<self>|なる最小のk } */ 00047 ilog2 = ymp_ilog2(self); ++ilog2; 00048 00049 bit_len = ilog2 / n; 00050 if (bit_len == 0) 00051 { 00052 if (ymp_is_zero(self)) ymp_assign_abs_digit(result, 0); 00053 else ymp_assign_abs_digit(result, 1); 00054 return; 00055 } 00056 if (ilog2 % n) ++bit_len; 00057 00058 ymp_alloca_initialize(&x, self->used * n + 1); 00059 for (i=0; i<bit_len/DIGIT_BIT; ++i) x.digits[i] = 0; 00060 x.digits[i] = 1u << (bit_len%DIGIT_BIT); 00061 x.used = ++i; 00062 00063 /* 今、x は (2**k)**n > |<self>| なる最小の2**k */ 00064 00065 00066 /* 作業領域確保 */ 00067 ymp_alloca_initialize(&tmp, self->used * n + 1); 00068 ymp_alloca_initialize(&x_prev, self->used * n + 1); 00069 00070 00071 /* f(x) = x**n - |<self>| に対するNetwon法 */ 00072 for (;;) 00073 { 00074 l_newton_iteration: 00075 ymp_assign(&x_prev, &x); 00076 00077 /* x_{i+1} = ((n-1) * x_i**n + a) / (n * x_i**(n-1)) */ 00078 ymp_pow(&tmp, &x_prev, n-1); /* tmp = x_i ** (n-1) */ 00079 00080 ymp_assign(&x, &tmp); /* x = x_i ** n */ 00081 ymp_mul(&x, &x, &x_prev); 00082 ymp_mul_digit(&x, &x, n-1); /* x = (n-1) * x_i**n */ 00083 ymp_add(&x, &x, self); /* (n-1) * x_i**n + a */ 00084 00085 ymp_mul_digit(&tmp, &tmp, n); /* tmp = n*x_i**(n-1) */ 00086 00087 ymp_div(&x, &x, &tmp); /* x = x_{i+1} */ 00088 00089 00090 if (x.used != x_prev.used) continue; /* まだ誤差が大きい */ 00091 00092 for (i=1; i<x.used; ++i) 00093 { 00094 if (x.digits[i] != x_prev.digits[i]) /* まだ誤差が大きい */ 00095 goto l_newton_iteration; /* Newton法続行 */ 00096 } 00097 00098 /* かなり収束した。現在の誤差の絶対値が1以下なら、あとは微調整 */ 00099 switch ((int)(x.digits[0] - x_prev.digits[0])) 00100 { 00101 case 0: 00102 ymp_assign_abs(result, &x); 00103 return; 00104 00105 case 1: 00106 for (;;) 00107 { 00108 ymp_pow(&tmp, &x, n); 00109 if (ymp_compare_abs(&tmp, self) > 0) break; 00110 ymp_add_digit(&x, &x, 1); 00111 } 00112 ymp_sub_digit(&x, &x, 1); 00113 ymp_assign_abs(result, &x); 00114 return; 00115 00116 case -1: 00117 for (;;) 00118 { 00119 ymp_pow(&tmp, &x, n); 00120 if (ymp_compare_abs(&tmp, self) <= 0) break; 00121 ymp_sub_digit(&x, &x, 1); 00122 } 00123 ymp_assign_abs(result, &x); 00124 return; 00125 } 00126 } 00127 } |