2

I'm trying to generate 12 digit random numbers in C, but it's always generating 10 digit numbers.

#include <stdio.h>
#include <time.h>
#include <stdlib.h>

void main()
{
   srand(time(NULL));
   long r = rand();
   r = r*100;
   printf("%ld",r);
}
Saurav Sahu
  • 13,038
  • 6
  • 64
  • 79
kulst
  • 144
  • 1
  • 10

4 Answers4

2

rand() returns an int value in the range of [0...RAND_MAX]

Based on the C spec, RAND_MAX >= 32767 and RAND_MAX <= INT_MAX.

Call rand() multiple times to create a wide value


unsigned long long rand_atleast12digit(void) {
  unsigned long long r = rand();
  #if RAND_MAX >= 999999999999
  #elif RAND_MAX >= 999999
    r *= RAND_MAX + 1ull;
    r += rand();
  #else
    r *= RAND_MAX + 1ull;
    r += rand();
    r *= RAND_MAX + 1ull;
    r += rand();
  #endif
  return r;
}

The above returns a number if the range of 0 to at least 999,999,999,999. To reduce that to only that range, code could use return r % 1000000000000;.


Using % likely does not create an balanced distribution of random numbers. Other posts address details of how to cope with that like this good one incorporated as follows.

#if RAND_MAX >= 999999999999
  #define R12DIGIT_DIVISOR (RAND_MAX/1000000000000)
#elif RAND_MAX >= 999999
  #define RAND_MAX_P1  (RAND_MAX+1LLU)
  #define R12DIGIT_DIVISOR ((RAND_MAX_P1*RAND_MAX_P1-1)/1000000000000)
#else
  #define RAND_MAX_P1  (RAND_MAX+1LLU)
  #define R12DIGIT_DIVISOR  ((RAND_MAX_P1*RAND_MAX_P1*RAND_MAX_P1-1)/1000000000000)
#endif

unsigned long long rand_12digit(void) {
    unsigned long long retval;
    do { 
        retval = rand_atleast12digit() / R12DIGIT_DIVISOR;
    } while (retval == 1000000000000);
    return retval;
}

Note that the quality of rand() is not well defined, so repeated calls may not provide high quality results.


OP's code fails if long is 32-bit as it lacks range for a 12 decimal digit values. @Michael Walz

If long is wide enough, *100 will always make the least 2 decimal digits 00 - not very random. @Alexei Levenkov

long r = rand();
r = r*100;
Community
  • 1
  • 1
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
1

The result of rand is int, which means you can't get a 12 digit number directly from it.

If you need value that is always 12 digits you need to make sure values fit in particular range.

Sample below assumes that you need just some of the numbers to be 12 digits - you just need 8 extra bits - so shifting and OR'ing results would produce number in 0x7fffffffff-0 range that would often result up to 12 digit output when printed as decimal:

r = rand();
r = (r << 8) | rand();

PS: Make sure the variable that will store the result is big enough to store the 12 digit number.

Gnqz
  • 3,292
  • 3
  • 25
  • 35
  • The unsigned long can go up to 4,294,967,295. and long to 2,147,483,647, which are 10 digit numbers. You need to "construct" yourself a 12 digit number, since your maximum result can go just up to 10 digits (limited by the return type of the rand function). – Gnqz Nov 01 '16 at 13:32
  • 3
    `(r << 8) | rand();` is _poor_ solution to extend the `rand()` range as it increases the chances for 1 bits dramatically. Better to use `(r << 8) ^ rand();`. Also unless `r` is a wider type than 32-bit, this approach will not work. – chux - Reinstate Monica Nov 01 '16 at 15:29
  • My focuse was on what is the cause of the problem and suggesting a way to resolve it. Thank you for the suggestion, will take it in mind. – Gnqz Nov 01 '16 at 15:50
  • 2
    @Gnqz `unsigned long can go up to 4,294,967,295. and long to 2,147,483,647` incorrect. C standard [doesn't state that `long` must be 32 bits](http://stackoverflow.com/q/589575/995714). It depends on compiler implementation. Moreover `int` **can** have more than 32 bits so it can definitely store a 12-digit number. Again it also depends on compiler implementation – phuclv Nov 01 '16 at 16:33
  • but r = rand(); r = (r << 8) ^ rand(); this code doesn't generate different number always generates 462669366470 this number. – kulst Nov 01 '16 at 18:25
  • another problem of yours is that you're assuming `RAND_MAX` has 32 bits. No, on Windows it's often 15 bits and on Linux it's 31 bits – phuclv Nov 02 '16 at 01:16
  • so the 32th bit will always be zero in this case – phuclv Nov 02 '16 at 01:29
  • your code also doesn't make sure that the result will always be less than 1e12 because a 40-bit number definitely can have 13 digits – phuclv Nov 02 '16 at 06:29
0

My simple way to generate random strings or numbers is :

static char *ws_generate_token(size_t length) {

    static char charset[] = "1234567890"; // generate numbers only
    //static char charset[] = "abcdefghijklmnopqrstuvwxyz1234567890"; to generate random string
    char *randomString = NULL;

    if (length) {
        randomString = malloc(sizeof(char) * (length + 1));

        if (randomString) {
            for (int n = 0; n < length; n++) {
                int key = rand() % (int)(sizeof(charset) -1);
                randomString[n] = charset[key];
            }

            randomString[length] = '\0';
        }
    }

    return randomString;
}

Explain the code

  1. Create an array of chars which will contains (numbers, alphabets ...etc)
  2. Generate a random number between [0, array length], let's name it X.
  3. Get the character at random X position in the array of chars.
  4. finally, add this character to the sequence of strings (or numbers) you want to have in return.

How to use it ?

#define TOKEN_LENGTH      12
char *token;

token = ws_generate_token(TOKEN_LENGTH);

conversion from string to int

int token_int = atol(token);

dont forget !

free(token); // free the memory when you finish
  • 1
    Ok, but the question is about generating 12-digits *numbers*, not strings. Also please note that an `int` might not be wide enough to store such numbers. You are proposing to use `atol` to convert the string, but what would be the returned numbers when the inputs are like `"z2"`, `"42b"` or `"nope"`? – Bob__ Feb 01 '23 at 16:08
  • Easy, put numbers only in the 'charset' this will generate string of numbers (ex: "127653986343") then use atol to convert it to int. – Samir RAMDANI Feb 12 '23 at 11:44
-3
    #include <stdio.h>
#include <stdlib.h>

int main()
{
   int i, n;
   time_t t;

   n = 5;

   /* Intializes random number generator int range */
   srand((unsigned) time(&t));

   /* Print 5 random numbers from 50 to back
   for( i = 0 ; i < n ; i++ ) 
   {
      printf("%d\n", rand() % 50);
   }

   return(0);
}
Ash Bilal
  • 1
  • 1
  • what are you doing? And how is `rand() % 50` printing a number from 0 to 32767? – phuclv Nov 02 '16 at 01:19
  • rand will print number with the different of five from where u want it to back or forward like above (50,45,40,35....) – Ash Bilal Nov 02 '16 at 06:08
  • 1
    how is it relevant to the OP's question? your program doesn't even generate numbers >= 50 – phuclv Nov 02 '16 at 06:18