Pelles C forum

C language => Beginner questions => Topic started by: dpanteli on April 20, 2012, 07:29:30 PM

Title: rand()%4
Post by: dpanteli on April 20, 2012, 07:29:30 PM
Hello,
Please can you help me? Why the following prints always 3?

#include <stdio.h>
#include <time.h>
#include <stdlib.h>
 
int main (void)
  {
   int i;
      srand((unsigned) time(NULL));
      i = rand() %4;

   printf("%d\n",i);

      return 0 ;
  }

Thank you in advanced
Dimitris Pantelios
Title: Re: rand()%4
Post by: czerny on April 20, 2012, 08:28:16 PM
rand() does not return real random numbers. It returns pseudo random numbers. They produce a sequence of numbers which look random. But the sequence as always identical if the start value of the sequence is identical. So if you want to produce different values, you should set the start value to something different with the function srand(). You can use time() to randomize this a little.

czerny
Title: Re: rand()%4
Post by: CommonTater on April 20, 2012, 10:14:34 PM
Hello,
Please can you help me? Why the following prints always 3?

#include <stdio.h>
#include <time.h>
#include <stdlib.h>
 
int main (void)
  {
   int i;
      srand((unsigned) time(NULL));
      i = rand() %4;

   printf("%d\n",i);

      return 0 ;
  }

Thank you in advanced
Dimitris Pantelios

Make a loop and tell it to print 20 or 30 numbers... see if the sequence is always the same.  It should not be.

Also, with such a small range (4) it's entirely possible the sequences generated from the seed (srand() ) by coincidence have been starting with 3.

You don't need the unsigned cast in your seed, srand() always builds sequences from 0 to RAND_MAX.



Title: Re: rand()%4
Post by: Bitbeisser on April 21, 2012, 07:03:25 AM
rand() does not return real random numbers. It returns pseudo random numbers. They produce a sequence of numbers which look random. But the sequence as always identical if the start value of the sequence is identical. So if you want to produce different values, you should set the start value to something different with the function srand(). You can use time() to randomize this a little.
That's what he already tried....
Quote from: CommonTater
Also, with such a small range (4) it's entirely possible the sequences generated from the seed (srand() ) by coincidence have been starting with 3.
That seems indeed to be the case. Just change the range to 5 (% 5) and you will see that the results will kind of alternate between 2 and 3...

Ralf
Title: Re: rand()%4
Post by: dpanteli on April 21, 2012, 09:46:22 AM
Yes, the sequences are different... However the strange is that the first number (as many times I tried) was always the same... Maybe by coincidence...
Although, when I tried to use rand()%3 then the first number of the sequenses are not always the same... Strange behaviour...
Title: Re: rand()%4
Post by: CommonTater on April 21, 2012, 04:37:17 PM
Yes, the sequences are different... However the strange is that the first number (as many times I tried) was always the same... Maybe by coincidence...
Although, when I tried to use rand()%3 then the first number of the sequenses are not always the same... Strange behaviour...

Try it with rand() % 5000 and see what the first number is...  I still think it's the very small range you're using.

Don't forget these are not true random numbers.  This is something computers don't do well. they are sequences of pseudo-random numbers generated by the srand() function.

You might try something like this to enhance the apparent randomness of small ranges...

Code: [Select]
srand(time(NULL));  // seed random number generator
rand();                 // discard first value

x = (rand() % 156) % 4;   //  start from a larger range

... some experimentation will help you find the best way for your own code.

Title: Re: rand()%4
Post by: Vortex on April 21, 2012, 07:26:52 PM
Hi dpanteli,

You can use the Windows timer to support the random number generator.
Title: Re: rand()%4
Post by: CommonTater on April 21, 2012, 09:47:17 PM
Hi dpanteli,

You can use the Windows timer to support the random number generator.

As in ...  srand(GetTickCount());     

That's a good one too.
Title: Re: rand()%4
Post by: ngohungcuong on August 04, 2018, 09:33:40 AM
I think it is error of srand and rand function. I test this code
srand(GetTickCount());
rand()%4;
it alway return same result.
Title: Re: rand()%4
Post by: ngohungcuong on August 04, 2018, 11:41:00 AM
i test below code
Code: [Select]
#include <windows.h>
#include <stdint.h>

void entry(void)
{
int t;
int i;
char szTg[100];
uint32_t count[4];
count[0] = 0;
count[1] = 0;
count[2] = 0;
count[3] = 0;

for (i = 0; i < 1000; ++i) {
srand(GetTickCount());
t = rand() % 4;
++count[t];
Sleep(1);
}
wsprintf(szTg, "%d %d %d %d", count[0], count[1], count[2], count[3]);
MessageBox(NULL, szTg, NULL, MB_OK);
ExitProcess(0);
}
then the result : count[3] is 1000
Title: Re: rand()%4
Post by: ngohungcuong on August 04, 2018, 11:54:04 AM
then i add msvcrt.lib to linker tab cause linker link to msvcrt.dll
program work fine

Title: Re: rand()%4
Post by: TimoVJL on August 04, 2018, 02:11:53 PM
It seem that in this case srand() in loop don't work well as it starts sequence again:(
A modified example to see generated rand() values:
Code: [Select]
#include <stdint.h>
#include <stdlib.h>
#pragma comment(lib, "user32")
//#pragma comment(lib, "msvcrt")
//#pragma comment(linker, "-subsystem:console")

int __stdcall GetTickCount(void);
void __stdcall Sleep(int);
uint32_t count[4];
//void __cdecl mainCRTStartup(void)
void main(void)
{
for (int i = 0; i < 60; ++i) {
int t,idx;
t = rand();
idx = t % 4;
++count[idx];
printf("%2d %2d %2d %2d %2d %d\n", count[0], count[1], count[2], count[3], idx, t);
Sleep(1);
}
return;
}
Also with
Code: [Select]
t = rand()/4;
idx = t % 4;
  PellesC gives more random numbers for that scale.
Title: Re: rand()%4
Post by: ika on September 04, 2018, 07:54:58 AM
You can just use the Microsoft Crypto API's instead:

Code: [Select]
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

int __cdecl main(void){

HCRYPTPROV cp;
int tgt;

(void)CryptAcquireContextA(&cp,NULL,NULL,PROV_RSA_FULL,CRYPT_VERIFYCONTEXT);

for(int i = 0; i < 30; i++){
CryptGenRandom(cp,sizeof(int),(void*)&tgt);
printf("%d\n",abs(tgt % 4));
}

(void)CryptReleaseContext(cp,0);

return EXIT_SUCCESS;
}

This seems to work for me, I can get some pretty random numbers using it at this range.
Title: Re: rand()%4
Post by: TimoVJL on September 04, 2018, 10:52:44 AM
Results: 1.08 - 2.83
Code: [Select]
#include <stdio.h>
#include <stdlib.h>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <wincrypt.h>

unsigned long count[4];

int __cdecl main(void){

HCRYPTPROV cp;
int tgt;

(void)CryptAcquireContextA(&cp,NULL,NULL,PROV_RSA_FULL,CRYPT_VERIFYCONTEXT);

for(int i = 0; i < 100; i++){
CryptGenRandom(cp,sizeof(int),(void*)&tgt);
int idx = abs(tgt % 4);
++count[idx];
//printf("%2d %2d %2d %2d %2d %d\n", count[0], count[1], count[2], count[3], idx, tgt);
}

(void)CryptReleaseContext(cp,0);
printf(" 1  2  3  4\n%2d %2d %2d %2d\n", count[0], count[1], count[2], count[3]);
int min=100, max=0;
for (int i=0; i<4; i++) {
if (count[i] < min) min = count[i];
if (count[i] > max) max = count[i];
}
printf("%0.2f %d %d\n", (double)max/min, min, max);
return EXIT_SUCCESS;
}
rand() based gives 1.08
Title: Re: rand()%4
Post by: ika on September 04, 2018, 12:23:18 PM
Here is the same code, again, but with the new crypto API. When I looked at MSDN it says that the old one has been deprecated...
Maybe not meaningful today, but their new API is pretty similar if it's just to generate some numbers. It even has a special setting for that.
Code: [Select]
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

#pragma comment(lib,"bcrypt.lib")

int __cdecl main(void){

BCRYPT_ALG_HANDLE bah;
int tgt;

BCryptOpenAlgorithmProvider(&bah,BCRYPT_RNG_ALGORITHM,NULL,0);

for(int i = 0; i < 30; i++){
BCryptGenRandom(bah,(void*)&tgt,sizeof(int),0);
printf("%d\n",abs(tgt) % 4);
}

BCryptCloseAlgorithmProvider(bah,0);

return EXIT_SUCCESS;
}