Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/132.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何确保rand生成的0到1之间的随机数不是0?_C++_Random - Fatal编程技术网

C++ 如何确保rand生成的0到1之间的随机数不是0?

C++ 如何确保rand生成的0到1之间的随机数不是0?,c++,random,C++,Random,我正在模拟一个排队模型,我需要用这个算法生成我的到达量。然而,我有时会得到0.000000作为随机值R1,并且不可能计算ln(0),因此过程停止。我如何避免得到0 我曾考虑将0.0000001添加到其中,但这不是很糟糕,因为我可能会得到大于1的值吗 #include<stdio.h> #include<conio.h> #include<math.h> #include<stdlib.h> #include<time.h> main(

我正在模拟一个排队模型,我需要用这个算法生成我的到达量。然而,我有时会得到0.000000作为随机值R1,并且不可能计算ln(0),因此过程停止。我如何避免得到0

我曾考虑将0.0000001添加到其中,但这不是很糟糕,因为我可能会得到大于1的值吗

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

main()
    {
        int a=3, b=4, T=500, I=0, l=1504;
        srand(time(NULL));
        float R1, R2, t=0, S[10000], f;

        printf("Utilizaremos la funcion at+b para el simular el poceso\n");
        while(t<T){
            R1=rand()/(double)RAND_MAX;
            t= t-log(R1)/l;
            R2=rand()/(double)RAND_MAX;
            f = a*t+b;
            if(R2<f/l){
                I=I+1;
                S[I]=t;
                printf(" \n I %d, R1 %f, R2 %f, t %f, S[i] %f", I,R1,R2,t,S[I]);
            }


        }
        getche();
        return 0;
}
#包括
#包括
#包括
#包括
#包括
main()
{
INTA=3,b=4,T=500,I=0,l=1504;
srand(时间(空));
浮点数R1,R2,t=0,S[10000],f;
printf(“在+b段模拟操作中的实用功能”);
虽然(t不是说
rand()
是一件好事,但是有效地避免零很容易:

double nzrand() {
  constexpr double max=RAND_MAX+1.;
  return (rand()+1.)/max;
}
这可以精确返回1;当然,使用
+2.
可以避免这一点


当然,更常见的方法是在[0,1]上生成随机值(这里,通过在分母上加1而不是分子),然后计算
log(1-x)

只要得到一个随机数,直到得不到0为止

double myrand()
{
    while(1)
    {
        double r = rand()/(double)RAND_MAX;
        if (r != 0)
            return r;
    }
}

...

R1 = myrand();  // Will not be 0

我可以想出两个简单的方法

  • 在[0,1]中生成一个数字,并从1中减去:

    R1 = rand() / (RAND_MAX + 1.0);
    R1 = 1.0 - R1;
    
  • 将rand()的结果加1,并相应地增加除数:

    R1 = (rand() + 1.0) / (RAND_MAX + 1.0);
    

  • <>这两个结果都是(0,1]、

    < P>中的一个新的更好的C++方法是使用C++ 11标准库< /P>的新方法。 使用,您可以将范围指定为
    double
    值,如
    (1e-12,1.0)
    。或者更好地使用
    (std::numeric_limits::min(),1.0)
    ,这将为您提供最小的
    double
    值,该值尚未为零,但仍在标准化(
    2.122e-314

    完整示例:

    #include <stdio.h>
    #include <math.h>
    #include <random>
    
    int main()
    {
        int a = 3, b = 4, T = 500, I = 0, l = 1504;
        std::random_device rndsource;
        std::minstd_rand rndgen(rndsource());
        std::uniform_real_distribution<double> dist(1e-12, 1.0);
        double R1, R2, t = 0, S[10000], f;
    
        printf("Utilizaremos la funcion at+b para el simular el poceso\n");
        while (t < T) {
            R1 = dist(rndgen);
            t = t - log(R1) / l;
            R2 = dist(rndgen);
            f = a * t + b;
            if (R2 < f / l) {
                I = I + 1;
                S[I] = t;
                printf(" I %d, R1 %f, R2 %f, t %f, S[i] %f\n", I, R1, R2, t, S[I]);
            }
        }
        return 0;
    }
    
    #包括
    #包括
    #包括
    int main()
    {
    INTA=3,b=4,T=500,I=0,l=1504;
    std::随机_设备rndsource;
    std::minstd_rand rndgen(rndsource());
    标准:均匀真实分布区(1e-12,1.0);
    双R1,R2,t=0,S[10000],f;
    printf(“在+b段模拟操作中的实用功能”);
    而(t

    std::minstd_rand
    是一种LCG,在大多数科学应用中非常快速且可用。为了更好地预测,请尝试使用
    std::mt19937
    PRNG。

    好的,下面是正确的答案

    • 首先,您应该使用C++11工具(或者,如果您使用的是C++03,则使用类似的BOOST随机库)
    • 其次,默认的双随机数生成需要至少53个尾数随机位,因此最好使用64位比特流生成器(以下示例中为mt19937_64)。因此,对rng的一次调用将生成一个双随机数,并且在64位平台上通常会更快
    • 第三,默认的统一双精度生成器生成严格[0…1]范围内的数字。使用1-R技巧将其推入(0…1)范围
    • 第四,您的代码有一个bug-很容易溢出数组的大小并导致内存损坏,因此,我添加了适当的保护
    • 最后-请不要像其他人建议的那样使用随机_设备。一般来说,您需要完全可重复的运行,所以最好控制种子
    代码,Visual C++2019,Win10 x64

    #include <cmath>
    #include <random>
    #include <cstdio>
    
    int main() {
        int a = 3, b = 4, T = 500, I = 0, l = 1504;
    
        double R1, R2, t = 0, S[10000], f;
    
        std::mt19937_64 rng{ 7719716254321ULL }; // init with known seed - reproducability
                                                 // no need in random device
        std::uniform_real_distribution<double> rnd{};
    
        printf("Utilizaremos la funcion at+b para el simular el poceso\n");
        while (t < T) {
            R1 = rnd(rng);
            t = t - log(1.0 - R1) / l;
            R2 = rnd(rng);
            f = a * t + b;
            if (R2 < f / l) {
                S[I] = t;
                printf(" I %d, R1 %f, R2 %f, t %f, S[i] %f\n", I, R1, R2, t, S[I]);
                ++I;
                if (I == sizeof(S) / sizeof(S[0]))
                    break;
            }
        }
        (void)getchar();
    
        return 0;
    }
    
    #包括
    #包括
    #包括
    int main(){
    INTA=3,b=4,T=500,I=0,l=1504;
    双R1,R2,t=0,S[10000],f;
    std::mt19937_64 rng{7719716254321ULL};//具有已知种子复制能力的init
    //无需在随机设备
    一致实分布rnd{};
    printf(“在+b段模拟操作中的实用功能”);
    而(t
    还有另一种可能性:

    double increment = 0.000000001;  // However small you need.
    double near_zero = 0.005;
    ...
    
    double nzrand() {
    
      double nzr = rand()/(double)RAND_MAX;
      if (nzr < near_zero) {
        nzr += increment;
      }
      return nzr;
    
    } // end nzrand()
    
    double increment=0.000000001;//无论需要多小。
    双近零=0.005;
    ...
    双nzrand(){
    双nzr=rand()/(双)rand_MAX;
    如果(nzr<接近零){
    nzr+=增量;
    }
    返回nzr;
    }//end nzrand()
    

    这只增加了一个小的增量,如果初始值短于1,它就永远不会超过一个,它永远不会返回零,最小可能的返回值是给定的增量。< /P>如果你得到0的随机数,又会怎样?在C++中你应该使用而不是<代码> RAND()/<代码>,如果这是C。(看起来是这样),请更新标签。兰德()被认为是有害的-斯蒂芬·T·拉瓦维,如果

    rand()
    可以返回
    INT\u MAX
    ,这可能会溢出。你应该将
    1.0
    添加到
    rand()
    而不是
    1
    @Kevin:当然-我这样做是为了
    rand\u MAX
    而不是
    rand()
    本身。编辑。