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

0

Я пытаюсь сделать модель бактерий просто для удовольствия, и я использую функцию 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
  • 0
    Изменение data type int to long long может быть связано с тем, что Population слишком сильно увеличен, поэтому его нельзя сохранить в int.
  • 0
    Я убедился, что в этом случае, население не превышает 10000, что идеально подходит для Int.
Показать ещё 4 комментария
Теги:
modeling

4 ответа

2
Лучший ответ
pow (1 + taxa, tempo_t)

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

unsigned long long

  • 0
    Проблема заключается в используемом методе, более фундаментально, чем в размере переменной. Население должно уменьшаться, как только оно превысит 10 000 человек, но, как оно есть в настоящее время, оно увеличивается до огромных размеров, а затем многократно сокращается с коэффициентом 0,7 до тех пор, пока оно не опустится ниже 10 000 человек. Это я не думаю, что нужно.
  • 0
    @ Тони, если это не так сложно, не могли бы вы предложить лучший метод?
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
  • 0
    Спасибо, я думаю, что понял. Я постараюсь исправить это. Секундочку
  • 0
    таким образом, поскольку рост такой медленный, функция round () всегда оценивает значение совокупности как 2.
Показать ещё 2 комментария
2

даже unsigned long long int не может удерживаться. Когда tempo_t> 895, тогда

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

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню