12

I've been working on this for some time and having a lot of trouble. I want to generate a random value from -1 to 1 for a calculation. I cant use the % operator because it is for integers only. I also tried using fmod() but I'm having difficulty here too.

What I was trying to use was...

double random_value;
random_value = fmod((double) rand(),2) + (-1);

it seems like it's not correct though. I also tried to seed srand with the time, but I think im doing something wrong there because it keeps throwing this error:

"error: expected declaration specifiers or '...' before time"

code:

srand((unsigned) time(&t));

any help with these problems would be appreciate.

Iharob Al Asimi
  • 52,653
  • 6
  • 59
  • 97
E Newmy
  • 185
  • 1
  • 1
  • 11
  • rand() still returns an integer, and then you are casting it to double. This means possible solutions are -1,0 and 1, no other double are possible. Look at [c-random-float-number-generation](http://stackoverflow.com/questions/686353/c-random-float-number-generation) – Lorenzo Belli Oct 10 '15 at 20:52
  • The answers provided so far (mine included) will not cover the full range of precision available in a `double`. How much precision do you need? – cp.engr Oct 10 '15 at 21:24
  • I edited my answer to reflect the precision limitations. Please give more info on your requirements if you want something "better". – cp.engr Oct 10 '15 at 21:43

11 Answers11

11

You can seed with time (once before all calls to rand) like this:

#include <time.h>

// ...
srand (time ( NULL));

With this function you can set the min/max as needed.

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

/* generate a random floating point number from min to max */
double randfrom(double min, double max) 
{
    double range = (max - min); 
    double div = RAND_MAX / range;
    return min + (rand() / div);
}

Source: [SOLVED] Random double generator problem (C Programming) at Ubuntu Forums

Then you would call it like this:

double myRand = randfrom(-1.0, 1.0);

Note, however, that this most likely won't cover the full range of precision available from a double. Without even considering the exponent, an IEEE-754 double contains 52 bits of significand (i.e. the non-exponent part). Since rand returns an int between 0 and RAND_MAX, the maximum possible value of RAND_MAX is INT_MAX. On many (most?) platforms, int is 32-bits, so INT_MAX is 0x7fffffff, covering 31 bits of range.

cp.engr
  • 2,291
  • 4
  • 28
  • 42
9

This will seed the random number generator and give a double in the range of -1.0 to 1.0

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

int main()
{
    double random_value;

    srand ( time ( NULL));

    random_value = (double)rand()/RAND_MAX*2.0-1.0;//float in range -1 to 1

    printf ( "%f\n", random_value);

    return 0;
}
user3121023
  • 8,181
  • 5
  • 18
  • 16
2

I think the best way to create a real random double is to use its structure. Here's an article about how float numbers are stored. As you see the only limiting condition for float to be between 1 and -1 is that the exponent value doesn't exceed 128.

Ieee754SingleDigits2Double converts string of 0s and 1s to a float variable and return it. I got it from the answers to this question.

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

double Ieee754SingleDigits2Double(const char s[32])
{
    double f;
    int sign, exp;
    unsigned int mant;
    int i;

    sign = s[0] - '0';

    exp = 0;
    for (i = 1; i <= 8; i++)
        exp = exp * 2 + (s[i] - '0');

    exp -= 127;

    if (exp > -127)
    {
        mant = 1; // The implicit "1."
        exp -= 23;
    }
    else
    {
        mant = 0;
        exp = -126;
        exp -= 23;
    }

    for (i = 9; i <= 31; i++)
        mant = mant * 2 + (s[i] - '0');

    f = mant;

    while (exp > 0)
        f *= 2, exp--;

    while (exp < 0)
        f /= 2, exp++;

    if (sign)
        f = -f;

    return f;
}

Here's the main function:

int main(void)
{
    srand ( time ( NULL));
    int i;
    char s[33];
    for(i = 0; i < 32; i++)
    {
        if(i == 1)
            continue;
        s[i] = rand() % 2 + '0';
    }
    s[1] = '0';
    s[32] = 0;
    printf("%s\n", s);
    printf("%+g\n", Ieee754SingleDigits2Double(s));

    return 0;
}
Claire Nielsen
  • 1,881
  • 1
  • 14
  • 31
0

Probably not a good idea to do so, but just because it works, here's a way of generating a random double between -1 and 1 included using /dev/urandom and cos():

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <math.h>

int main()
{
  int fd;
  double x;

  fd = open("/dev/urandom", O_RDONLY);
  if (fd == -1)
    return (1);
  read(fd, &x, sizeof(x));
  close(fd);
  x = cos(x);
  printf("%f\n", x);
  return (0);
}
yoones
  • 2,394
  • 1
  • 16
  • 20
  • Lol at creative use of cosine. – Daniel Stevens Oct 10 '15 at 23:22
  • 3
    Every thousand calls or so, you will get a NaN. (Not because of cos, although i believe cos(infinity) is also NaN, but you will very rarely get an infinity.) What is related to cos is that the rng here will not be uniformly-distributed. – rici Oct 10 '15 at 23:33
0

Similar to other answers, with a few improvements you might need to keep your code a bit safer and coherent:

#include <stdlib.h> /* srand and rand */
#include <unistd.h> /* getpid */
#include <time.h> /* time */
#include <errno.h> /* errno */
#include <math.h> /* NAN  */

/* generate a float random number in a range */
float randmm(float min, float max)
{
     static int first = -1;
     if((first = (first<0)))
         srand(time(NULL)+getpid());
     if(min>=max)
         return errno=EDOM, NAN;

     return min + (float)rand() / ((float)RAND_MAX / (max - min));
}

Going through the code we have:

  • A static variable first that will guarantee you don't forget to seed the pseudo-random number generator (PRNG). The logic is simple and elegant: in the first call, first is -1, it is then compared to be less than zero, which updates it to true (value 1). The second call asks if first, now 1, is less than zero, which is false (value 0), so srand() isn't called. Third is a charm, they say, so now first, which is 0, is asked if it is less than zero, which keeps being false for this and the next iterations.
  • Next, you might need to guarantee that min-max is not zero, or else you will get a nasty division by zero (or NAN). For that we shall explicitly cause the correct error. Using errno.h to set the error and math.h to have NAN (not a number) macro available. It is not advisable to compare two floats for equality (like if(min==max)) so it is not a good idea to try to invert the min/max values in case min is greater, and have a third option in case they are equal. Just simplify your if with only two options: it is right, or it is not.
  • Finally, I've preferred to work with float instead of double to not give too much trust on what this function can generate. A 32 bits integer (which is RAND_MAX) can only do so much. To fill a float is reasonable, for all bits. float has only 23 bits for the number, plus 8 for exponent. If you use double you will be mislead and overconfident in the capacity of this function. If you need a true double, consider using /dev/urand or other proper true random number generator (TRNG).
  • The last line, the return, is just a simple equation. I guess you can figure that out easily. I just like to explicitly cast to float so I can see the code's intention besides the compiler's interpretation.
  • And of course, to use as OP want, just call as float x = randmm(-1.0, 1.0);
DrBeco
  • 11,237
  • 9
  • 59
  • 76
  • 1
    I don't like this approach. Moving the seed into the generator function introduces a (small) runtime cost, and makes testing more difficult (not repeatable). The way you expressed your `first` check is needlessly cryptic, IMO (better to use a `bool`, and don't combine the assignment and check on one line). OP did not specify a platform; `getpid()` is not portable. Good catch about preventing division by 0, but I'm not a fan of putting errors in `errno`, especially in user code. – cp.engr Aug 31 '18 at 20:32
  • The runtime cost is picayune. But regarding the more sound critic about testing, one can easily add a `if(DEBUG)` condition to use. About the "criptic", I guess it was, yes. Actually, that is the nice part of the answer. Yep, `getpid()` may need a portable similar if OP need it. But the idea is out there. Thanks for the zero-division cumpliment. And, well, `errno` is there to be used. All in all, thanks for your comment. I hope this answer at least inspired your creativity. My best. – DrBeco Aug 31 '18 at 20:53
  • Adding `if(DEBUG)` for testing changes the behavior, which introduces the question of whether or how well you're really testing. Cryptic code (your `first` implementation) hurts maintainability. I don't think our other differences of opinion are worth pursuing. Thanks for taking my constructive criticism as intended. – cp.engr Aug 31 '18 at 21:44
0

This answer mostly applies to people looking for random doubles on x86_64 machines. Being a long time C user (since late 1980s), I gave up caring what the RAND_MAX value of the day is.

Also, the srand(time(NULL) indicates to me that the numbers are generated with some quasi random number generator of (at least to me) unknown quality. And all that, while you are just 1 assembly instruction away from CPU random numbers on modern x86_64 machines.

So, the code below uses rdrand via intrinsics, which is known to be a full 64bit random number as a source of randomness. This way, at least, you have sufficient bits to generate a double without further ado. If - instead - you opted for C library rand() and it returned a 32 bit value, you might have not enough bits for a 64 floating point number. And there is no randl(), randul() or alike in Ansi C, afaik.

But - if you look at the signature of the _rdrand_step() intrinsic, it seems like this instruction might fail under certain conditions. (Load related, some say). So, in the code below, it might (or might not) be a good idea to write a while() loop or something like that around the intrinsic call.

#include <stdio.h>
#include <stdint.h>
#include <immintrin.h>
#include <float.h>

int randomf64(double minVal, double maxVal, double* out) {
    if (NULL == out)
        return 0;
    uint64_t result = 0ULL;
    // cast in next line works for amd64 (x86_64) on linux at least.
    int rc = _rdrand64_step((unsigned long long*)&result);
    if(rc) {
        double unscaled = (double)result/(double)UINT64_MAX;
        *out = minVal + (maxVal - minVal) * unscaled;
        return 1;
    }
    return 0;
}

int main(int argc, const char* argv[]) {
    size_t nvals = 1;
    if(argc > 1) {
        nvals = atol(argv[1]);
    }
    // We want to see if all that "can fail under stress" thing happens...
    double *values = malloc(nvals * sizeof(double));
    if (NULL != values) {
        for(size_t i = 0; i < nvals; ++i ) {
            if(!randomf64(-100.0,100.0, &values[i])) {
                printf("boom! after %lu random numbers generated.\n",
                        i);
                free(values);
                exit(-1);
            }
        }
        for(size_t i = 0; i < nvals; ++i) {
            int Digs = DECIMAL_DIG;
            printf("%lu %.*e\n", i, Digs, values[i]);
        }
        free(values);
    }
    return 0;
}

If you supply an integer as a command line argument, it generates a respective number of random doubles and stores them in a heap allocated array. This allows for testing if that "sporadic failing" might happen. I tried several times with up to 1E6 values created in a burst and it never failed (on some cheap AMD CPU).

In order to compile this, e.g. with clang, I used:

clang -mrdrnd -O3 -std=c17 -o r64i r64intrin.c

Please note, that you have to enable the usage of the intrinsic with -mrdrnd for the compiler to be happy.

BitTickler
  • 10,905
  • 5
  • 32
  • 53
0

For higher precision:

double random() {
  unsigned int rnd;
  rnd = (rand() & 0x7fff) | ((rand() & 0x7fff) << 15);
  return (double)rnd / (double)(0x3fffffff);
}

Of course it would be possible to add a full 32 bit precision or even a long precision to this. But RAND_MAx is as someone stated 15bits, and would need more calls to rand() and then 'or' them together in a similar fashion.

Erik
  • 101
  • 5
0

There are a lot of rand(min, max) solutions here, so I won't comment on that. If you need full range random double (from lowest possible to highest possible):

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

// full range uint32_t rand - from 0 to UINT32_MAX
uint32_t rand32() {
  // in in mingw32 RANDMAX is 32767 
#if RAND_MAX < 32768
  union {
      uint16_t i[2];
      uint32_t l;
  } n;
  uint16_t t; // we need two more bits
  n.i[0] = rand(); // first 16 bits
  n.i[1] = rand(); // last 16 bits
  t = rand();
  if ((t & 0x01) != 0) { // add the MSbit
    n.i[0] |= 0x8000;
  }
  if ((t & 0x02) != 0) { // add the MSbit
    n.i[1] |= 0x8000;
  }
  return n.l;
#else
  // USUALLY RAND_MAX is 2147483647 (or  0x7FFFFFFF) - missing the MSbit
  uint32_t l;
  uint32_t t;
  l = rand();
  t = rand();
  if ((t & 0x01) != 0) { // add the MSbit
    l |= 0x80000000;
  }
  return l;
#endif
}

// full range random double
double randDouble() {
  union {
      uint32_t i[2];
      double d;
  } num;
  num.i[0] = rand32();
  num.i[1] = rand32();

  return num.d;
}

int main(int argc, char *argv[]) {
  time_t result = time(NULL);
  srand(result);

  printf("random uint32: %0x08X\n", rand32());
  // up to 200 digits after the decimal point. Sometimes the number is really small
  printf("random double: %lE\n", randDouble());
}
NickSoft
  • 3,215
  • 5
  • 27
  • 48
-1

After search a lot to this and getting tips from around, i create this function to generate random double number in specific range.

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

double random(double min, double max) 
{
    //used it to generate new number each time
    srand( (unsigned int) time(NULL) );

    double randomNumber, range , tempRan, finalRan;
    //generate random number form 0.0 to 1.0
    randomNumber = (double)rand() / (double)RAND_MAX;
    //total range number from min to max eg. from -2 to 2 is 4
    //range used it to pivot form -2 to 2 -> 0 to 4 for next step
    range = max - min
    //illustrate randomNumber to range
    //lets say that rand() generate 0.5 number, thats it the half 
    //of 0.0 to 1.0, show multiple range with randomNumber we get the
    //half in range. eg 4 * 0.5 = 2
    tempRan = randomNumber * range;
    //add the min to tempRan to get the correct random in ours range
    //so in ours example we have: 2 + (-2) = 0, thats the half in -2 to 2
    finalRan = tempRan + min;
    return finalRan;
}

This is working illustrating the rate % of random number in ours range.

  • This function will not create random numbers at all, because it calls `srand()` every time. – VLL Nov 28 '19 at 08:30
  • srand() uses its argument seed as a seed for a new sequence of pseudo-random numbers to be returned by subsequent calls to rand(). Some people find it convenient to use the return value of the time() function as the argument to srand(), as a way to ensure random sequences of random numbers. [from ibm doc](https://www.ibm.com/support/knowledgecenter/en/SSLTBW_2.1.0/com.ibm.zos.v2r1.bpxbd00/srand.htm) – Paulitos Germanos Dec 03 '19 at 21:52
  • 2
    1) time() changes value only once per second. This function will return same value every second. 2) If you call srand() every time, you start a new sequence every time. Do you know the numbers are still evenly distributed if you only use the first number of each sequence? For example, rand() could return the seed as the first value, and in such case the return values would be steadily increasing. – VLL Dec 04 '19 at 07:40
-1
random_value = (double)rand() * rand() / (RAND_MAX * RAND_MAX) * 2 - 1;
-1

There is an easy way to get random value in range [-1.0; 1.0] Trigonometric function sine takes a number returned by rand() and returns value in that range.

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

/* macro returning value in range [-1.0; 1.0] */
#define double_rand() ( sin(rand()) )

int main(void) {
    int i;

    srand(time(NULL));

    /* 20 tests to show result */
    for ( i = 0; i < 20; ++i )
        printf("%f\n", double_rand());

    return 0;
}

On linux systems don't forget to link the math library
$ gcc -Wall sin_rand.c -lm
$ ./a.out
0.014475
-0.751095
-0.650722
0.995111
-0.923760
...

Izya Budman
  • 107
  • 2
  • 4
  • Can you [edit] your question and explain the code? Code-only answers tend to be considered low-quality as people cannot learn from them and end up copying & pasting some code they don't understand from the interwebs. See [answer]. – Robert Dec 29 '19 at 15:31
  • 2
    Generally when someone says they want a random number within some range, without specifying a probability distribution, they mean a flat distribution, i.e. equal probability of outputting any particular number in that range. Using sine makes it not flat, as pictured in this question: https://stats.stackexchange.com/questions/126273/probability-distribution-for-a-noisy-sine-wave – cp.engr Jan 11 '21 at 02:17