diff options
Diffstat (limited to 'src/num.c')
-rw-r--r-- | src/num.c | 83 |
1 files changed, 68 insertions, 15 deletions
@@ -3515,8 +3515,9 @@ bc_num_print(BcNum* restrict n, BcBigDig base, bool newline) // Print the sign. if (BC_NUM_NEG(n)) bc_num_putchar('-', true); - // Print the leading zero if necessary. - if (BC_Z && BC_NUM_RDX_VAL(n) == n->len) + // Print the leading zero if necessary. We don't print when using + // scientific or engineering modes. + if (BC_Z && BC_NUM_RDX_VAL(n) == n->len && base != 0 && base != 1) { bc_num_printHex(0, 1, false, !newline); } @@ -3815,7 +3816,7 @@ void bc_num_irand(BcNum* restrict a, BcNum* restrict b, BcRNG* restrict rng) { BcNum atemp; - size_t i, len; + size_t i; assert(a != b); @@ -3835,24 +3836,76 @@ bc_num_irand(BcNum* restrict a, BcNum* restrict b, BcRNG* restrict rng) assert(atemp.num != NULL); assert(atemp.len); - len = atemp.len - 1; + if (atemp.len > 2) + { + size_t len; + + len = atemp.len - 2; - // Just generate a random number for each limb. - for (i = 0; i < len; ++i) + // Just generate a random number for each limb. + for (i = 0; i < len; i += 2) + { + BcRand dig; + + dig = bc_rand_bounded(rng, BC_BASE_RAND_POW); + + b->num[i] = (BcDig) (dig % BC_BASE_POW); + b->num[i + 1] = (BcDig) (dig / BC_BASE_POW); + } + } + else { - b->num[i] = (BcDig) bc_rand_bounded(rng, BC_BASE_POW); + // We need this set. + i = 0; } - // Do the last digit explicitly because the bound must be right. But only - // do it if the limb does not equal 1. If it does, we have already hit the - // limit. - if (atemp.num[i] != 1) + // This will be true if there's one full limb after the two limb groups. + if (i == atemp.len - 2) { - b->num[i] = (BcDig) bc_rand_bounded(rng, (BcRand) atemp.num[i]); - b->len = atemp.len; + // Increment this for easy use. + i += 1; + + // If the last digit is not one, we need to set a bound for it + // explicitly. Since there's still an empty limb, we need to fill that. + if (atemp.num[i] != 1) + { + BcRand dig; + BcRand bound; + + // Set the bound to the bound of the last limb times the amount + // needed to fill the second-to-last limb as well. + bound = ((BcRand) atemp.num[i]) * BC_BASE_POW; + + dig = bc_rand_bounded(rng, bound); + + // Fill the last two. + b->num[i - 1] = (BcDig) (dig % BC_BASE_POW); + b->num[i] = (BcDig) (dig / BC_BASE_POW); + + // Ensure that the length will be correct. If the last limb is zero, + // then the length needs to be one less than the bound. + b->len = atemp.len - (b->num[i] == 0); + } + // Here the last limb *is* one, which means the last limb does *not* + // need to be filled. Also, the length needs to be one less because the + // last limb is 0. + else + { + b->num[i - 1] = (BcDig) bc_rand_bounded(rng, BC_BASE_POW); + b->len = atemp.len - 1; + } + } + // Here, there is only one limb to fill. + else + { + // See above for how this works. + if (atemp.num[i] != 1) + { + b->num[i] = (BcDig) bc_rand_bounded(rng, (BcRand) atemp.num[i]); + b->len = atemp.len - (b->num[i] == 0); + } + else b->len = atemp.len - 1; } - // We want 1 less len in the case where we skip the last limb. - else b->len = len; bc_num_clean(b); |