【问题标题】:Population growth model not corresponding to expectations人口增长模型不符合预期
【发布时间】:2015-03-02 00:22:13
【问题描述】:

我试图制作一个细菌模型只是为了好玩,我正在使用 pow(a, b) 函数作为计算人口增长的函数。当细菌种群达到其环境所能提供的最大食物单位数量时,由于个体之间的竞争,它会下降 70%。我将结果保存到 txt,以便稍后绘制。我遇到的问题是种群正确振荡,直到我达到 t = 900 附近的多个繁殖周期,然后种群默认为 0。 代码如下,希望你不要介意葡萄牙语写的变量和函数的名称。

bool
check_aliemento (unsigned long int *pop)
{
    if (*pop >= MAX_ALIMENTO) return false;
    return true;
}

unsigned long int
replicaBacteria (unsigned long int *popInit, unsigned int tempo_t, double taxa)
{
    unsigned long int nextPop = round ((*popInit) * 
                static_cast<double> (pow (1 + taxa, tempo_t))); 
                //I'm almost sure that the problem happens in this pow() function
    while (! check_aliemento (&nextPop))
    {
        nextPop = (0.7 * nextPop);
    }
    return nextPop;
}



   int
main ( int argc, char** argv )
{
    unsigned long int a = 2;
    ofstream myfile;
    myfile.open ( "C:\\Users\\Pedro\\Desktop\\values.txt" );
    for ( unsigned int i; i < 1000; i ++ )
    {
        unsigned long int pop = replicaBacteria ( &a, i, 0.05 );
        myfile << pop << " ==> time = " << i;
        myfile << "\r\n";
    }
    myfile.close ( );
    return 0;
}

示例输出:

8080 ==> time = 872
8484 ==> time = 873
8909 ==> time = 874
9354 ==> time = 875
9822 ==> time = 876
7219 ==> time = 877
7580 ==> time = 878
7958 ==> time = 879
8357 ==> time = 880
8775 ==> time = 881
9214 ==> time = 882
9675 ==> time = 883
7110 ==> time = 884
7466 ==> time = 885
7839 ==> time = 886
8232 ==> time = 887
8643 ==> time = 888
9075 ==> time = 889
9529 ==> time = 890
7003 ==> time = 891
7354 ==> time = 892
7721 ==> time = 893
8108 ==> time = 894
8513 ==> time = 895
0 ==> time = 896
0 ==> time = 897
0 ==> time = 898
0 ==> time = 899
0 ==> time = 900

【问题讨论】:

  • 更改您的data type int to long long 可能是由于 Population 增加太多,因此无法存储在 int 中。
  • 我已经确保在这种情况下,人口不会超过 10000,这完全适合 int。
  • i 的初始值是多少?
  • 编译器自动设置为0。gcc之美!
  • 是的,你的 nextPop 有问题,通过打印检查它的值。

标签: c++ c modeling


【解决方案1】:

您正在溢出long int nextPop。这是因为您正在计算人口增长,就好像它连续 896 代没有中断,然后才减少人口直到它低于您的魔法极限(这里是 10,000,您说)。

解决此问题的一种方法是在每次迭代后保留总体并将其增长 5%,然后在必要时将结果减少到 70%。

因此,您需要 pop = replicaBacteria ( pop, 0.05 ); 之类的东西,而不是 unsigned long int pop = replicaBacteria ( &amp;a, i, 0.05 );(在循环之前声明变量),然后 replicaBacteria 应该简单地将其输入乘以 5% 并在必要时缩放到结果的 70%。

以下代码被编辑以生成可以为我编译和运行的东西

像这样:

#include <cmath>
#include <fstream>
#include <iostream>

#define MAX_ALIMENTO 10000

double
replicaBacteria (double popInit, double taxa)
{
    double nextPop = popInit * (1 + taxa); 
    while (nextPop >= MAX_ALIMENTO)
    {
        nextPop = (0.7 * nextPop);
    }
    return nextPop;
}



   int
main ( int argc, char** argv )
{
    std::ofstream myfile( "/tmp/out.txt" );
    double pop = 2;
    unsigned int i;
    for ( i=0; i < 1000; i ++ )
    {
        pop = replicaBacteria ( pop, 0.05 );
        myfile << round(pop) << " ==> time = " << i;
        myfile << "\r\n";
    }
    myfile.close ( );
    return 0;
}

输出:

2 ==> time = 0
2 ==> time = 1
2 ==> time = 2
2 ==> time = 3
3 ==> time = 4
3 ==> time = 5
3 ==> time = 6
3 ==> time = 7
3 ==> time = 8
3 ==> time = 9
3 ==> time = 10
4 ==> time = 11
...
8925 ==> time = 990
9371 ==> time = 991
9840 ==> time = 992
7232 ==> time = 993
7594 ==> time = 994
7974 ==> time = 995
8372 ==> time = 996
8791 ==> time = 997
9230 ==> time = 998
9692 ==> time = 999

【讨论】:

  • 谢谢,我想我明白了。我会尝试纠正它。只需一秒钟
  • 这样,因为增长太慢,所以round()函数总是将population的值评估为2。
  • 要么以大于 2 的值开始种群(例如,因为您可以手动计算第一代,例如 50 代),要么将变量设为 double 而不是 int(您可以让它打印一个四舍五入的数字,但继续存储小数结果。)我将编辑我的回复,看看它是否有帮助。
【解决方案2】:
pow (1 + taxa, tempo_t)

显然long int 不能容纳2^900 所以您在这里看到的是整数溢出,使用可以容纳较大值的数据类型,例如

unsigned long long

【讨论】:

  • 问题出在使用的方法上,比变量的大小更根本。人口一旦超过 10,000 就会下降,但现在的方式是,它会增长到巨大的规模,然后以 0.7 倍的倍数反复下降,直到低于 10,000。我认为这不是我们想要的。
  • @Tony 如果不麻烦的话,您介意提供一个更好的方法吗?
【解决方案3】:

即使是 unsigned long long int 也不能​​成立。 当 tempo_t > 895 时

unsigned long long int nextPop = round ((*popInit) * 
                    static_cast<double> (pow (1 + taxa, tempo_t)));

这个表达式的计算结果为零,所以你必须减少细菌的寿命。

【讨论】:

    【解决方案4】:

    稍微改变你的函数以了解数字何时变为零:

    unsigned long int
    replicaBacteria (unsigned long int *popInit, unsigned int tempo_t, double taxa)
    {
       double r = round ((*popInit) * static_cast<double> (pow (1 + taxa, tempo_t))); 
       std::cout << r << std::endl;
       unsigned long int nextPop = r;
       std::cout << nextPop << std::endl;
    
       //I'm almost sure that the problem happens in this pow() function
       while (! check_aliemento (&nextPop))
       {
          nextPop = (0.7 * nextPop);
       }
       return nextPop;
    }
    

    我看到以下输出:

    1.84269e+19
    18426916303946758144
    8513 ==> time = 895
    1.93483e+19
    0
    0 ==> time = 896
    2.03157e+19
    0
    0 ==> time = 897
    

    这是在使用 g++ 4.8.2 的 64 位 Linux 机器上。由于您从896 开始看到零,因此可以安全地假设您的编译器存在完全相同的问题。 unsigned long int可以表示的最大数小于1.93483e+19

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-26
      • 1970-01-01
      • 2021-01-19
      • 1970-01-01
      • 2017-07-28
      • 1970-01-01
      相关资源
      最近更新 更多