NO

Author Topic: rand()%4  (Read 4172 times)

dpanteli

  • Guest
rand()%4
« 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

czerny

  • Guest
Re: rand()%4
« Reply #1 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

CommonTater

  • Guest
Re: rand()%4
« Reply #2 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.




Offline Bitbeisser

  • Global Moderator
  • Member
  • *****
  • Posts: 760
Re: rand()%4
« Reply #3 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
« Last Edit: April 21, 2012, 07:33:08 am by Bitbeisser »

dpanteli

  • Guest
Re: rand()%4
« Reply #4 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...

CommonTater

  • Guest
Re: rand()%4
« Reply #5 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.

« Last Edit: April 21, 2012, 04:43:43 pm by CommonTater »

Offline Vortex

  • Member
  • *
  • Posts: 511
    • http://www.vortex.masmcode.com
Re: rand()%4
« Reply #6 on: April 21, 2012, 07:26:52 pm »
Hi dpanteli,

You can use the Windows timer to support the random number generator.
Code it... That's all...

CommonTater

  • Guest
Re: rand()%4
« Reply #7 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.

Offline ngohungcuong

  • Member
  • *
  • Posts: 5
Re: rand()%4
« Reply #8 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.

Offline ngohungcuong

  • Member
  • *
  • Posts: 5
Re: rand()%4
« Reply #9 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
« Last Edit: August 04, 2018, 11:58:24 am by ngohungcuong »

Offline ngohungcuong

  • Member
  • *
  • Posts: 5
Re: rand()%4
« Reply #10 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


Offline TimoVJL

  • Global Moderator
  • Member
  • *****
  • Posts: 1767
Re: rand()%4
« Reply #11 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.
« Last Edit: August 05, 2018, 02:43:33 pm by TimoVJL »
May the source be with you

Offline ika

  • Member
  • *
  • Posts: 12
Re: rand()%4
« Reply #12 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.
« Last Edit: September 04, 2018, 11:02:27 am by ika »

Offline TimoVJL

  • Global Moderator
  • Member
  • *****
  • Posts: 1767
Re: rand()%4
« Reply #13 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
May the source be with you

Offline ika

  • Member
  • *
  • Posts: 12
Re: rand()%4
« Reply #14 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;
}