From d908299c15dbd10163483e359d8f4f02c42546c5 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 2 Aug 2017 17:06:43 +0200 Subject: [PATCH 1/4] Problem: randof() strikes again Solution: explicitly floorf() the generated value before converting to int Signed-off-by: Jim Klimov --- include/czmq_prelude.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/czmq_prelude.h b/include/czmq_prelude.h index 54cbf493f..3c9a03314 100644 --- a/include/czmq_prelude.h +++ b/include/czmq_prelude.h @@ -426,12 +426,12 @@ typedef struct { // RAND_MAX, random() returns a 32-bit value all filled with random bits. #if (defined (__WINDOWS__)) || (defined (__UTYPE_IBMAIX)) \ || (defined (__UTYPE_HPUX)) || (defined (__UTYPE_SUNOS)) || (defined (__UTYPE_SOLARIS)) -# define randof(num) (int) ((float) (num) * rand () / (RAND_MAX + 1.0)) +# define randof(num) (int) ( floorf( (float) (num) * rand () / (RAND_MAX + 1.0)) ) #else # if defined(RAND_MAX) -# define randof(num) (int) ((float) (num) * (random () % RAND_MAX) / (RAND_MAX + 1.0)) +# define randof(num) (int) ( floorf( (float) (num) * (random () % RAND_MAX) / (RAND_MAX + 1.0)) ) # else -# define randof(num) (int) ((float) (num) * (uint32_t)random () / (UINT32_MAX + 1.0)) +# define randof(num) (int) ( floorf( (float) (num) * (uint32_t)random () / (UINT32_MAX + 1.0)) ) # endif #endif From 054493978c74d2f285edf3a484a020605db6329f Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 2 Aug 2017 17:20:07 +0200 Subject: [PATCH 2/4] Smother randof() in (float) casts so compilers are happy and more likely to do a predictable job --- include/czmq_prelude.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/czmq_prelude.h b/include/czmq_prelude.h index 3c9a03314..bcaa5f5a9 100644 --- a/include/czmq_prelude.h +++ b/include/czmq_prelude.h @@ -426,12 +426,12 @@ typedef struct { // RAND_MAX, random() returns a 32-bit value all filled with random bits. #if (defined (__WINDOWS__)) || (defined (__UTYPE_IBMAIX)) \ || (defined (__UTYPE_HPUX)) || (defined (__UTYPE_SUNOS)) || (defined (__UTYPE_SOLARIS)) -# define randof(num) (int) ( floorf( (float) (num) * rand () / (RAND_MAX + 1.0)) ) +# define randof(num) (int) ( floorf( (float) ( (float)(num) * (float)(rand ()) / ((float)RAND_MAX + 1.0)) ) ) #else # if defined(RAND_MAX) -# define randof(num) (int) ( floorf( (float) (num) * (random () % RAND_MAX) / (RAND_MAX + 1.0)) ) +# define randof(num) (int) ( floorf( (float) ( (float)(num) * (float)(random () % RAND_MAX) / ((float)RAND_MAX + 1.0)) ) ) # else -# define randof(num) (int) ( floorf( (float) (num) * (uint32_t)random () / (UINT32_MAX + 1.0)) ) +# define randof(num) (int) ( floorf( (float) ( (float)(num) * (float)(uint32_t)random () / ((float)UINT32_MAX + 1.0)) ) ) # endif #endif From 0d8ca035952d69cb0e2a78a4a8c2b1669e089439 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 2 Aug 2017 18:15:14 +0200 Subject: [PATCH 3/4] Assert a few use-cases of randof() where it is simple to implement --- src/test_zgossip.c | 2 ++ src/zhashx.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/test_zgossip.c b/src/test_zgossip.c index b260b9e89..f71e8d410 100644 --- a/src/test_zgossip.c +++ b/src/test_zgossip.c @@ -144,6 +144,8 @@ main (int argn, char *argv []) int item_nbr; for (item_nbr = 0; item_nbr < set_size; item_nbr++) { node_nbr = randof (swarm_size); + assert (node_nbr != swarm_size); + assert (node_nbr < swarm_size); zstr_sendm (nodes [node_nbr], "PUBLISH"); zstr_sendfm (nodes [node_nbr], "key-%d", item_nbr); zstr_send (nodes [node_nbr], "value"); diff --git a/src/zhashx.c b/src/zhashx.c index 3cb03c469..e1e2723ea 100644 --- a/src/zhashx.c +++ b/src/zhashx.c @@ -1269,6 +1269,8 @@ zhashx_test (bool verbose) srandom ((unsigned) time (NULL)); for (iteration = 0; iteration < 25000; iteration++) { testnbr = randof (testmax); + assert (testnbr != testmax); + assert (testnbr < testmax); if (testset [testnbr].exists) { item = (char *) zhashx_lookup (hash, testset [testnbr].name); assert (item); From 85c352a481dc15541e1b71dd144ac0a9da53809a Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 2 Aug 2017 18:15:47 +0200 Subject: [PATCH 4/4] Self-test the randof() adherence to its limits by running many-many attempts --- src/zhashx.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/zhashx.c b/src/zhashx.c index e1e2723ea..eab1ba4d6 100644 --- a/src/zhashx.c +++ b/src/zhashx.c @@ -1292,6 +1292,16 @@ zhashx_test (bool verbose) zhashx_destroy (&hash); assert (hash == NULL); + // Test randof() limits - should be within (0..testmax) + // Note: This test can take a while on systems with weak floating point HW + testmax = 999; + for (iteration = 0; iteration < 10000000; iteration++) { + testnbr = randof (testmax); + assert (testnbr != testmax); + assert (testnbr < testmax); + assert (testnbr >= 0); + } + // Test destructor; automatically copies and frees string values hash = zhashx_new (); assert (hash);