diff options
author | Kevin Ryde <user42@zip.com.au> | 2000-06-04 00:34:11 +0200 |
---|---|---|
committer | Kevin Ryde <user42@zip.com.au> | 2000-06-04 00:34:11 +0200 |
commit | 3ce85e5315c16f6d0cf79cafed589c7809ac4f18 (patch) | |
tree | 2792e247622180379dc804bd967b7e580849ca7e /mpz/bin_uiui.c | |
parent | bb07f225e202670cca187979484b4fb3c30b40d8 (diff) | |
download | gmp-3ce85e5315c16f6d0cf79cafed589c7809ac4f18.tar.gz |
* mpz/bin_uiui.c: Fix result for n==0 and n==k.
This is per a bug-gmp report by Hans J Lahne <hjlas@online.no>, but
not using the patch offerred, instead taking the opportunity to
flatten out the nested conditionals.
The diff for this revision is a bit horrible, but only the initial
setups have changed, the main loop has just been reindented.
Diffstat (limited to 'mpz/bin_uiui.c')
-rw-r--r-- | mpz/bin_uiui.c | 121 |
1 files changed, 63 insertions, 58 deletions
diff --git a/mpz/bin_uiui.c b/mpz/bin_uiui.c index 8035303c8..813e35e25 100644 --- a/mpz/bin_uiui.c +++ b/mpz/bin_uiui.c @@ -33,73 +33,78 @@ mpz_bin_uiui (r, n, k) unsigned long int k; #endif { + unsigned long int i, j; + mp_limb_t nacc, kacc; + unsigned long int cnt; + + /* bin(n,k) = 0 if k>n. */ if (n < k) - /* This special case is a good idea since the unsigned variable n would - else become negative. It is not an exception that is mathematically - necessary. */ - mpz_set_ui (r, 0); - else { - unsigned long int i, j; - mp_limb_t nacc, kacc; - unsigned long int cnt; + mpz_set_ui (r, 0); + return; + } - /* Rewrite bin(n,k) as bin(n,n-k) if that is simpler to compute. */ - if (k > n / 2) - k = n - k; + /* Rewrite bin(n,k) as bin(n,n-k) if that is smaller. */ + k = MIN (k, n-k); + + /* bin(n,0) = 1 */ + if (k == 0) + { + mpz_set_ui (r, 1); + return; + } - j = n - k + 1; - mpz_set_ui (r, j); + j = n - k + 1; + mpz_set_ui (r, j); - /* Initialize accumulators. */ - nacc = 1; - kacc = 1; + /* Initialize accumulators. */ + nacc = 1; + kacc = 1; - cnt = 0; - for (i = 2; i <= k; i++) - { - mp_limb_t n1, n0, k1, k0; + cnt = 0; + for (i = 2; i <= k; i++) + { + mp_limb_t n1, n0, k1, k0; - j++; + j++; #if 0 - /* Remove common multiples of 2. This will allow us to accumulate - more in nacc and kacc before we need a bignum step. It would make - sense to cancel factors of 3, 5, etc too, but this would be best - handled by sieving out factors. Alternatively, we could perform a - gcd of the accumulators just as they have overflown, and keep - accumulating until the gcd doesn't remove a significant factor. */ - while (((nacc | kacc) & 1) == 0) - { - nacc >>= 1; - kacc >>= 1; - } + /* Remove common multiples of 2. This will allow us to accumulate + more in nacc and kacc before we need a bignum step. It would make + sense to cancel factors of 3, 5, etc too, but this would be best + handled by sieving out factors. Alternatively, we could perform a + gcd of the accumulators just as they have overflown, and keep + accumulating until the gcd doesn't remove a significant factor. */ + while (((nacc | kacc) & 1) == 0) + { + nacc >>= 1; + kacc >>= 1; + } #else - cnt = ((nacc | kacc) & 1) ^ 1; - nacc >>= cnt; - kacc >>= cnt; + cnt = ((nacc | kacc) & 1) ^ 1; + nacc >>= cnt; + kacc >>= cnt; #endif - /* Accumulate next multiples. */ - umul_ppmm (n1, n0, nacc, j); - umul_ppmm (k1, k0, kacc, i); - if (n1 != 0) - { - /* Accumulator overflow. Perform bignum step. */ - mpz_mul_ui (r, r, nacc); - nacc = j; - mpz_tdiv_q_ui (r, r, kacc); - kacc = i; - } - else - { - if (k1 != 0) abort (); - /* Save new products in accumulators to keep accumulating. */ - nacc = n0; - kacc = k0; - } - } - - /* Take care of whatever is left in accumulators. */ - mpz_mul_ui (r, r, nacc); - mpz_tdiv_q_ui (r, r, kacc); + /* Accumulate next multiples. */ + umul_ppmm (n1, n0, nacc, j); + umul_ppmm (k1, k0, kacc, i); + if (n1 != 0) + { + /* Accumulator overflow. Perform bignum step. */ + mpz_mul_ui (r, r, nacc); + nacc = j; + mpz_tdiv_q_ui (r, r, kacc); + kacc = i; + } + else + { + if (k1 != 0) abort (); + /* Save new products in accumulators to keep accumulating. */ + nacc = n0; + kacc = k0; + } } + + /* Take care of whatever is left in accumulators. */ + mpz_mul_ui (r, r, nacc); + mpz_tdiv_q_ui (r, r, kacc); } |