人口增长模式与预期不符
Population growth model not corresponding to expectations
我试图制作一个细菌模型只是为了好玩,我正在使用 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
你溢出了 long int
nextPop
。这是因为你在计算人口增长时,就好像它在 896 代人中是不间断的,然后才减少人口,直到它低于你的魔法极限(你说这里是 10,000)。
解决这个问题的一种方法是在每次迭代后保留人口并将其增长 5%,然后在必要时将结果削减到 70%。
所以你想要 pop = replicaBacteria ( pop, 0.05 );
之类的东西而不是 unsigned long int pop = replicaBacteria ( &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
pow (1 + taxa, tempo_t)
显然 long int
不能容纳 2^900
所以你在这里看到的是整数溢出 使用可以容纳大值的数据类型
unsigned long long
即使是 unsigned long long int 也不能容纳。
当 tempo_t > 895 时
unsigned long long int nextPop = round ((*popInit) *
static_cast<double> (pow (1 + taxa, tempo_t)));
此表达式的计算结果为零,因此您必须减少细菌的寿命。
稍微改变一下函数以了解数字何时变为零:
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
这是在 64 位 Linux 机器上使用 g++ 4.8.2。由于您看到从 896
开始为零,因此可以安全地假设您的编译器存在完全相同的问题。 unsigned long int
能表示的最大数小于1.93483e+19
.
我试图制作一个细菌模型只是为了好玩,我正在使用 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
你溢出了 long int
nextPop
。这是因为你在计算人口增长时,就好像它在 896 代人中是不间断的,然后才减少人口,直到它低于你的魔法极限(你说这里是 10,000)。
解决这个问题的一种方法是在每次迭代后保留人口并将其增长 5%,然后在必要时将结果削减到 70%。
所以你想要 pop = replicaBacteria ( pop, 0.05 );
之类的东西而不是 unsigned long int pop = replicaBacteria ( &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
pow (1 + taxa, tempo_t)
显然 long int
不能容纳 2^900
所以你在这里看到的是整数溢出 使用可以容纳大值的数据类型
unsigned long long
即使是 unsigned long long int 也不能容纳。 当 tempo_t > 895 时
unsigned long long int nextPop = round ((*popInit) *
static_cast<double> (pow (1 + taxa, tempo_t)));
此表达式的计算结果为零,因此您必须减少细菌的寿命。
稍微改变一下函数以了解数字何时变为零:
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
这是在 64 位 Linux 机器上使用 g++ 4.8.2。由于您看到从 896
开始为零,因此可以安全地假设您的编译器存在完全相同的问题。 unsigned long int
能表示的最大数小于1.93483e+19
.