生成-1和1之间的随机双精度

时间:2015-10-10 20:49:42

标签: c

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

我试图使用的是......

double random_value;
random_value = fmod((double) rand(),2) + (-1);
但是,它似乎不正确。我也试着用时间播种srand,但我认为我在那里做错了,因为它一直在抛出这个错误:

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

代码:

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

任何有关这些问题的帮助都会受到赞赏。

9 个答案:

答案 0 :(得分:5)

这会使随机数生成器播种,并在-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;
}

答案 1 :(得分:3)

您可以按时间播种(一次拨打rand之前一次),如下所示:

#include <time.h>

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

使用此功能,您可以根据需要设置最小/最大值。

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

来源:[SOLVED] Random double generator problem (C Programming) Ubuntu Forums

然后你会这样称呼:

double myRand = randfrom(-1.0, 1.0);

但请注意,这很可能不会涵盖double提供的所有精确度。甚至没有考虑指数,IEEE-754 double包含52位有效数(即非指数部分)。由于randint0之间返回RAND_MAX,因此RAND_MAX的最大可能值为INT_MAX。在许多(大多数?)平台上,int为32位,因此INT_MAX0x7fffffff,覆盖31位范围。

答案 2 :(得分:1)

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

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

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

这是主要功能:

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

答案 3 :(得分:1)

与其他答案类似,通过一些改进,您可能需要保持代码更安全和连贯:

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

浏览我们的代码:

  • 静态变量first,可以保证您不会忘记为伪随机数生成器(PRNG)播种。逻辑简单而优雅:在第一次调用中,first为-1,然后将其比较为小于零,将其更新为 true (值1)。第二个调用询问first(现在为1)是否小于零,即 false (值为0),因此srand()未被调用。他们说,第三个是魅力,所以现在first,即0,会被问到它是否小于零,这对于此次和下次迭代都是假的。
  • 接下来,你可能需要保证min-max不为零,否则你会得到一个讨厌的除以零(或NAN)。为此,我们将明确地导致正确的错误。使用errno.h设置错误,math.h使用NAN(非数字)宏。不建议比较两个浮点数是否相等(如if(min==max)),因此在min更大的情况下尝试反转最小/最大值并不是一个好主意,如果它们相等则有第三个选项。只需使用两个选项简化if:它是正确的,或者不是。
  • 最后,我更倾向于使用float而不是double来对这个函数可以生成的内容给予太多信任。 32位整数(RAND_MAX)只能做这么多。对于所有位,填充float是合理的。 float数字只有23位,而指数只有8位。如果您使用double,则会对此功能的容量产生误导和过度自信。如果您需要真正的双倍,请考虑使用/dev/urand或其他正确的真随机数生成器(TRNG)。
  • 最后一行,即返回,只是一个简单的等式。我想你可以轻松搞清楚。我只想明确地转向float,这样除了编译器的解释之外,我还可以看到代码的意图。
  • 当然,要用作OP想要的,只需拨打float x = randmm(-1.0, 1.0);
  • 即可

答案 4 :(得分:0)

这样做可能不是一个好主意,但仅仅因为它有效,这里使用/dev/urandomcos()来生成-1到1之间的随机双倍:

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

答案 5 :(得分:0)

经过大量搜索并从中获取提示后,我创建此函数以生成特定范围内的随机双数。

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

这说明了我们范围内随机数的比率。

答案 6 :(得分:0)

有一种简单的方法可以获取[-1.0; 1.0]三角函数正弦采用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;
}

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

答案 7 :(得分:0)

此答案主要适用于在x86_64机器上寻找随机双打的人。 作为长期的C用户(自1980年代后期以来),我放弃了关心当日的RAND_MAX值。

此外,srand(time(NULL)向我表明,这些数字是由(至少对我而言)质量未知的某种准随机数生成器生成的。而且,尽管您只有1条汇编指令与现代x86_64计算机上的CPU随机数相距甚远。

因此,下面的代码通过内部函数使用rdrand,该函数被称为完整的64位随机数,作为随机性的来源。这样,至少,您有足够的位来生成双精度,而无需费心。如果-相反-您选择了C库rand()并且它返回了32位值,则可能没有足够的位来容纳64个浮点数。而且,Afaik的Ansi C中没有randl(), randul()等。

但是-如果您查看_rdrand_step()内在函数的签名,则该指令在某些情况下可能会失败。 (与负载有关,有人说)。因此,在下面的代码中,(或可能不)在固有调用周围编写while()循环或类似内容是一个好主意。

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

如果您提供整数作为命令行参数,则会生成一个相应的 随机双精度数并将它们存储在分配给堆的数组中。 这允许测试是否可能发生“零星失败”。我尝试了一次,最多创建了一个1E6值,但从未失败(在某些廉价的AMD CPU上)。

为了进行编译,例如与clang一起使用:

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

请注意,必须启用-mrdrnd中的内在函数才能使编译器满意。

答案 8 :(得分:-1)

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