Модель роста населения не соответствует ожиданиям

Я пытаюсь сделать модель бактерий просто для удовольствия, и я использую функцию pow (a, b) как функцию для расчета роста населения. Когда популяция бактерий достигает максимального количества пищевых единиц, которое может обеспечить ее среда, она уменьшается на 70% в результате конкуренции между людьми. Я сохраняю результаты в текстовом формате, чтобы я мог построить его позже. У меня проблема в том, что популяция колеблется правильно, пока я не достигну числа циклов размножения около 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

0

Решение

pow (1 + taxa, tempo_t)

очевидно long int не может держать 2^900 так что вы видите здесь, целочисленное переполнение использовать тип данных, который может содержать большие значения, такие как

unsigned long long

2

Другие решения

даже без знака long long int не может удержаться.
Когда tempo_t> 895, то

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

Это выражение оценивается как ноль, поэтому вы должны сократить время жизни бактерий.

2

Немного измените свою функцию, чтобы понять, когда число становится равным нулю:

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,

2

Вы переполнены long int nextPop, Это потому, что вы рассчитываете прирост населения, как если бы он был непрерывным в течение 896 поколений, и только после этого сокращаете население, пока оно не упадет ниже вашего магического предела (10 000 здесь, вы говорите).

Чтобы решить эту проблему, нужно сохранить популяцию после каждой итерации и увеличить ее на 5%, а затем сократить результат до 70%, если это необходимо.

Так что вместо unsigned long int pop = replicaBacteria ( &a, i, 0.05 );хочешь что-то вроде pop = replicaBacteria ( pop, 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
2
По вопросам рекламы [email protected]