1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-22 17:35:59 +03:00

Don't use floor() in _bitset_with_random_bits

Use _even_rand() function instead of floor() in _bitset_with_random_bits().
floor() function is missing in dietlibc (on architectures other than x86).
Moreover using floor() to clip rand results does not assure even result
distribution. _even_rand() uses integer arithmetic only and is designed to
return evenly distributed results.

> Looks OK to me. It took a while to decipher what is the exact meaning of
> the loop in _even_rand (to a non-pseudorandomness-expert) but I am
> fairly comfortable with it now. If I understand this correctly, it
> rejects numbers that come from an "incomplete" slice of the RAND_MAX
> space (considering the number space [0, RAND_MAX] is divided into some
> "max"-sized slices and at most a single smaller slice, between [n*max,
> RAND_MAX] for suitable n -- numbers from this last slice are discarded
> because they could distort the distribution in favour of smaller
> numbers).

Signed-off-by: Przemyslaw Iskra <sparky <at> pld-linux.org>
Reviewed-by: Petr Rockai <prockai <at> redhat.com>
This commit is contained in:
Zdenek Kabelac 2010-10-13 12:18:53 +00:00
parent bbdd3d40bd
commit 7c9fd3ea84
3 changed files with 25 additions and 6 deletions

View File

@ -125,8 +125,7 @@ AC_STRUCT_TM
################################################################################ ################################################################################
dnl -- Check for functions dnl -- Check for functions
AC_SEARCH_LIBS([floor], [m], , [AC_MSG_ERROR(bailing out)]) AC_CHECK_FUNCS([ftruncate gethostname getpagesize \
AC_CHECK_FUNCS([floor ftruncate gethostname getpagesize \
gettimeofday memset mkdir mkfifo rmdir munmap nl_langinfo setenv setlocale \ gettimeofday memset mkdir mkfifo rmdir munmap nl_langinfo setenv setlocale \
strcasecmp strchr strcspn strspn strdup strncasecmp strerror strrchr \ strcasecmp strchr strcspn strspn strdup strncasecmp strerror strrchr \
strstr strtol strtoul uname], , [AC_MSG_ERROR(bailing out)]) strstr strtol strtoul uname], , [AC_MSG_ERROR(bailing out)])

View File

@ -1015,6 +1015,29 @@ uint64_t extents_from_size(struct cmd_context *cmd, uint64_t size,
return (uint64_t) size / extent_size; return (uint64_t) size / extent_size;
} }
/*
* Return random integer in [0,max) interval
*
* The loop rejects numbers that come from an "incomplete" slice of the
* RAND_MAX space (considering the number space [0, RAND_MAX] is divided
* into some "max"-sized slices and at most a single smaller slice,
* between [n*max, RAND_MAX] for suitable n -- numbers from this last slice
* are discarded because they could distort the distribution in favour of
* smaller numbers.
*/
static unsigned _even_rand( unsigned *seed, unsigned max )
{
unsigned r, ret;
/* make sure distribution is even */
do {
r = (unsigned) rand_r( seed );
ret = r % max;
} while ( r - ret > RAND_MAX - max );
return ret;
}
static dm_bitset_t _bitset_with_random_bits(struct dm_pool *mem, uint32_t num_bits, static dm_bitset_t _bitset_with_random_bits(struct dm_pool *mem, uint32_t num_bits,
uint32_t num_set_bits, unsigned *seed) uint32_t num_set_bits, unsigned *seed)
{ {
@ -1037,7 +1060,7 @@ static dm_bitset_t _bitset_with_random_bits(struct dm_pool *mem, uint32_t num_bi
/* Perform loop num_set_bits times, selecting one bit each time */ /* Perform loop num_set_bits times, selecting one bit each time */
while (i++ < num_bits) { while (i++ < num_bits) {
/* Select a random bit between 0 and (i-1) inclusive. */ /* Select a random bit between 0 and (i-1) inclusive. */
bit_selected = (unsigned) floor(i * (rand_r(seed) / (RAND_MAX + 1.0))); bit_selected = _even_rand(seed, i);
/* /*
* If the bit was already set, set the new bit that became * If the bit was already set, set the new bit that became

View File

@ -111,9 +111,6 @@
/* Define to 1 if you have the <fcntl.h> header file. */ /* Define to 1 if you have the <fcntl.h> header file. */
#undef HAVE_FCNTL_H #undef HAVE_FCNTL_H
/* Define to 1 if you have the `floor' function. */
#undef HAVE_FLOOR
/* Define to 1 if you have the `fork' function. */ /* Define to 1 if you have the `fork' function. */
#undef HAVE_FORK #undef HAVE_FORK