Я пытаюсь сделать модель бактерий просто для удовольствия, и я использую функцию pow (a, b) как функцию для расчета роста населения. Когда популяция бактерий попадает в максимальное количество единиц пищи, которые может обеспечить ее окружающая среда, она уменьшается на 70% в результате конкуренции между отдельными лицами. Я сохраняю результаты в txt, поэтому я могу построить его позже. Проблема, с которой я сталкиваюсь, состоит в том, что население колеблется правильно, пока не достигнет ряда циклов воспроизведения arount 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
Измените свою функцию немного, чтобы понять, когда число становится равным нулю:
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
даже unsigned long long int не может удерживаться. Когда tempo_t> 895, тогда
unsigned long long int nextPop = round ((*popInit) *
static_cast<double> (pow (1 + taxa, tempo_t)));
Это выражение оценивается до нуля, поэтому вам нужно уменьшить время жизни бактерий.
data type int to long long
может быть связано с тем, что Population слишком сильно увеличен, поэтому его нельзя сохранить в int.