Я пытаюсь сделать модель бактерий просто для удовольствия, и я использую функцию 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
pow (1 + taxa, tempo_t)
очевидно long int
не может держать 2^900
так что вы видите здесь, целочисленное переполнение использовать тип данных, который может содержать большие значения, такие как
unsigned long long
даже без знака 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
,
Вы переполнены 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