Branch: Tag:

2016-03-29

2016-03-29 15:47:14 by Henrik Grubbström (Grubba) <grubba@grubba.org>

Gmp.mpz [Random]: Adjusted off by one error in the result range.

Adjusts the result value range for _random() to be one less than earlier.
This makes it conform to the behaviour of random() on normal integers.
Previously you got a surprise at the point where integers get converted
to bignums.

2065:       unsigned bits = mpz_sizeinbase(THIS, 2);    unsigned bytes = ((bits-1)>>3)+1; +  unsigned popcount = mpz_popcount(THIS);    -  +  if (((bits & 0x07) == 1) && (popcount == 1)) { +  /* An even number of bytes of random data. */ +  bytes--; +  } +     push_int(bytes);    apply_svalue(&sp[-2], 1);    if (TYPEOF(sp[-1]) != T_STRING)
2074:    sp[-1].u.string->size_shift != 0)    Pike_error("Wrong size random string generated.\n");    -  // We are asked to simply create @[bytes] of random data. -  if( (bits%8)==0 && mpz_popcount(THIS)==bits ) -  { +  if (bits > (bytes<<3)) { +  /* We've decreased the number of bytes above. +  * Ie we have the special case of an even number of random bytes. +  */    mpz_import(OBTOMPZ(res), bytes, 1, 1, 0, 0, sp[-1].u.string->str);    pop_stack();    goto done;
2090:    pop_stack();       unsigned char mask = (1<<(bits%8))-1; +  if (popcount == 1) { +  /* An even number of bits. +  * Ie the most significant bit of the masked result +  * should always be zero, so we can shrink the mask. +  */ +  mask >>= 1; +  }    if(mask) str[0] = mask & str[0];       for(int i=0; i<1000; i++)    {    mpz_import(OBTOMPZ(res), bytes, 1, 1, 0, 0, str); -  if( mpz_cmp(THIS, OBTOMPZ(res))>=0 ) +  if( mpz_cmp(THIS, OBTOMPZ(res)) > 0 )    {    free(str);    goto done;