C语言 生成 -1 和 1 之间的随机双精度值

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/33058848/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 12:10:07  来源:igfitidea点击:

Generate a random double between -1 and 1

c

提问by Eric Newman

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.

我已经为此工作了一段时间,但遇到了很多麻烦。我想生成一个从 -1 到 1 的随机值进行计算。我不能使用 % 运算符,因为它仅用于整数。我也尝试使用,fmod()但我在这里也遇到了困难。

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:

虽然它似乎不正确。我也试图用时间来播种 srand,但我认为我在那里做错了,因为它不断抛出这个错误:

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

code:

代码:

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

any help with these problems would be appreciate.

对这些问题的任何帮助将不胜感激。

采纳答案by user3121023

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

这将为随机数生成器提供种子,并在 -1.0 到 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;
}

回答by cp.engr

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

你可以rand像这样用时间播种(在所有调用之前一次):

#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

来源:[解决]随机双发生器问题(C编程)Ubuntu论坛

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 doublecontains 52 bits of significand (i.e. the non-exponent part). Since randreturns an intbetween 0and RAND_MAX, the maximum possible value of RAND_MAXis INT_MAX. On many (most?) platforms, intis 32-bits, so INT_MAXis 0x7fffffff, covering 31 bits of range.

但是请注意,这很可能不会涵盖double. 甚至不考虑指数,IEEE-754 double包含 52 位有效数(即非指数部分)。由于rand一个回报int之间0RAND_MAX,的最大可能值RAND_MAXINT_MAX。在许多(大多数?)平台,int是32位,所以INT_MAX0x7fffffff,覆盖范围31个比特。

回答by Mehrshad

I think the best way to create a real random double is to use its structure. Here'san 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.

我认为创建真正的随机双精度的最好方法是使用它的结构。是一篇关于如何存储浮点数的文章。如您所见,浮点数介于 1 和 -1 之间的唯一限制条件是指数值不超过 128。

Ieee754SingleDigits2Doubleconverts string of 0s and 1s to a float variable and return it. I got it from the answers to thisquestion.

Ieee754SingleDigits2Double将 0 和 1 的字符串转换为浮点变量并返回它。我从这个问题的答案中得到了它。

#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;
}

回答by Dr Beco

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 firstthat will guarantee you don't forget to seed the pseudo-random number generator (PRNG). The logic is simple and elegant: in the first call, firstis -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.hto set the error and math.hto 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 ifwith only two options: it is right, or it is not.
  • Finally, I've preferred to work with floatinstead of doubleto 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 floatis reasonable, for all bits. floathas only 23 bits for the number, plus 8 for exponent. If you use doubleyou will be mislead and overconfident in the capacity of this function. If you need a true double, consider using /dev/urandor 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 floatso 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);
  • 一个静态变量first,可确保您不会忘记为伪随机数生成器 (PRNG) 设置种子。逻辑简单而优雅:在第一次调用中,first为 -1,然后比较小于零,将其更新为true(值 1)。第二个调用询问first现在 1 是否小于零,这是错误的(值为 0),因此srand()没有被调用。他们说,第三个是魅力所在,所以 nowfirst是 0,被询问它是否小于零,这对于这次和下一次迭代来说一直是假的。
  • 接下来,您可能需要保证 min-max 不为零,否则您将得到一个令人讨厌的除以零(或 NAN)。为此,我们将明确地引起正确的错误。使用errno.h设置错误,并math.hNAN(非数字)宏可用。不建议比较两个浮点数是否相等(如if(min==max)),因此在 min 较大的情况下尝试反转最小值/最大值并不是一个好主意,如果它们相等,则有第三个选项。只需if使用两个选项来简化您的操作:它是对的,或者不是。
  • 最后,我更喜欢与之合作,float而不是double对这个函数可以生成的内容给予太多信任。一个 32 位整数(即RAND_MAX)只能做这么多。填充 afloat是合理的,对于所有位。float数字只有 23 位,指数加上 8 位。如果您使用double此功能,您将被误导和过度自信。如果您需要真正的双精度,请考虑使用/dev/urand或其他适当的真随机数生成器(TRNG)。
  • 最后一行,返回,只是一个简单的等式。我想你可以很容易地弄清楚这一点。我只是喜欢显式地强制转换,float这样除了编译器的解释之外,我还可以看到代码的意图。
  • 当然,要用作 OP,只需调用 float x = randmm(-1.0, 1.0);

回答by yoones

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/urandomand cos():

这样做可能不是一个好主意,但仅仅因为它有效,这里有一种使用/dev/urandomand生成 -1 和 1 之间的随机双精度的方法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);
}

回答by Izya Budman

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.

有一种简单的方法可以在 [-1.0; 范围内获得随机值;1.0] 三角函数 sine 接受 rand() 返回的数字并返回该范围内的值。

#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
...

在 linux 系统上不要忘记链接数学库
$ gcc -Wall sin_rand.c -lm
$ ./a.out
0.014475
-0.751095
-0.650722
0.995111
-0.923760
...

回答by Андр?й Немченко

random_value = (double)rand() * rand() / (RAND_MAX * RAND_MAX) * 2 - 1;

回答by Paulitos Germanos

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.

这正在说明我们范围内随机数的百分比。