summaryrefslogtreecommitdiff
path: root/mpz/bin_uiui.c
diff options
context:
space:
mode:
authorKevin Ryde <user42@zip.com.au>2000-06-04 00:34:11 +0200
committerKevin Ryde <user42@zip.com.au>2000-06-04 00:34:11 +0200
commit3ce85e5315c16f6d0cf79cafed589c7809ac4f18 (patch)
tree2792e247622180379dc804bd967b7e580849ca7e /mpz/bin_uiui.c
parentbb07f225e202670cca187979484b4fb3c30b40d8 (diff)
downloadgmp-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.c121
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);
}