Sign in to follow this  
ReubenESTD

Natural logarithms, exponential growth and C++

Recommended Posts

Ok so I am currently working on a complex console game in which the player takes on the role of an all powerful AI which controls the subconscious of a humanoid population. Many factors will be simulated in this game which will directly or indirectly effect birth/death-rate. This humanoid population will start at 1000 and increase until it reaches 15 billion when the game ends.

I wish to create a function in which a user input time increment and a global variable that represents yearly population increase can define the exponential population growth.

Ok so here is my formula (written in purely mathematical syntax no c++)

P = Ip(e^-kt)

Where
P = population
Ip = initial population
k = exponential constant
t = time

So inputing my numbers into this I get:

15,000,000,000 = 1000(2.718281828^-kt)
Or
15,000,000 = 2.718281828^-kt

ln(15,000,000) = k.t (ln e)

ln e = 16.524...

So
t=(16.524/k)(ln 15,000,000)

What I need to know is
1. Is this formula correct?
2. How can I make it so that t is the subject?
3. How can I best write this in C++ as a function or class with k as a global variable?

Thankyou for any help in advance, I am 15 and this maths is way beyond what I do in school.

Share this post


Link to post
Share on other sites
[quote name='White Dwarf' timestamp='1302737811' post='4798194']
Ok so I am currently working on a complex console game in which the player takes on the role of an all powerful AI which controls the subconscious of a humanoid population. Many factors will be simulated in this game which will directly or indirectly effect birth/death-rate. This humanoid population will start at 1000 and increase until it reaches 15 billion when the game ends.

I wish to create a function in which a user input time increment and a global variable that represents yearly population increase can define the exponential population growth.

Ok so here is my formula (written in purely mathematical syntax no c++)

P = Ip(e^-kt)

Where
P = population
Ip = initial population
k = exponential constant
t = time

So inputing my numbers into this I get:

15,000,000,000 = 1000(2.718281828^-kt)
Or
15,000,000 = 2.718281828^-kt

ln(15,000,000) = k.t (ln e)

ln e = 16.524...

So
t=(16.524/k)(ln 15,000,000)

What I need to know is
1. Is this formula correct?
2. How can I make it so that t is the subject?
3. How can I best write this in C++ as a function or class with k as a global variable?

Thankyou for any help in advance, I am 15 and this maths is way beyond what I do in school.
[/quote]

That looks like pretty impressive maths considering your age. Good to see you getting into it early. We're only just doing that sort of stuff and I'm nearly 4 years older than you. The formula you have looks like a fairly standard exponential growth equation, I'm not sure why you have a minus sign on your power of e though, so we'll get rid of that.

ln e = 1 not 16.524

So rearranging for t, you'd get:
t = (ln 15,000,000)/k

And the c++ function for ln is called log(). You'll have to include the math header files. I know you might not understand what a logarithm is, but ln is just log to the base e. C++ defaults to base e. If you want a base 10 logarithm, normally written as log in maths, you'd use log10().

So written in c++ your formula for t would be.

[code]
double k = //insert your constant
double t = log(15000000)/k
[/code]

That would work out the time taken for your population to reach your limit.

To work out the population number after a time interval, you can use this method:

[code]
double t = //insert your time
double k = //insert your constant
double kt = k*t
double e = 2.71828183;
double P = 1000*pow(e,kt)
[/code]

I guess you'll just have to play around with values of k until you find one that works with your game.

Hope this helps!

Share this post


Link to post
Share on other sites
[quote name='win_crook' timestamp='1302739759' post='4798205']
That looks like pretty impressive maths considering your age. Good to see you getting into it early. We're only just doing that sort of stuff and I'm nearly 4 years older than you. The formula you have looks like a fairly standard exponential growth equation, I'm not sure why you have a minus sign on your power of e though, so we'll get rid of that.

ln e = 1 not 16.524

So rearranging for t, you'd get:
t = (ln 15,000,000)/k

And the c++ function for ln is called log(). You'll have to include the math header files. I know you might not understand what a logarithm is, but ln is just log to the base e. C++ defaults to base e. If you want a base 10 logarithm, normally written as log in maths, you'd use log10().

So written in c++ your formula for t would be.

[code]
double k = //insert your constant
double t = log(15000000)/k
[/code]

That would work out the time taken for your population to reach your limit.

To work out the population number after a time interval, you can use this method:

[code]
double t = //insert your time
double k = //insert your constant
double kt = k*t
double e = 2.71828183;
double P = 1000*pow(e,kt)
[/code]

I guess you'll just have to play around with values of k until you find one that works with your game.

Hope this helps!
[/quote]

Hey, your explanation has made it much clearer, so thankyou!

Anyway, I tried to incorporate it with my program and I keep getting the result 0.
Here is the code:
[code]

#include <iostream>
#include <cmath>
#include <math.h>
#include <stdio.h>

using namespace std;

void otherfactors(); //temporary function to effect births and deaths.
void population(); // natural logarithm for population growth.
void birthdeathrate(); //yearly birth and death rate
void timestepfoward(); //performs all neccasary proceedures to fast foward time

int births;//births over a year
int deaths;//deaths over a year
double popgrowth; // population growth over a year (percentage)
double t; //time in years
int currentyear=1; //current year
double pop_at_start_of_period=1000; //holds the population at the start of each period.


int main()
{
otherfactors();
timestepfoward();
return 0;
}


void timestepfoward(){
cout << "\n\nIt is currently year " << currentyear << " and the population is " << pop_at_start_of_period << ".\n";
cout << "How many years would you like to skip? ";
cin >> t;
birthdeathrate();
population();
currentyear = t+currentyear;
cout << "\nIt is now year " << currentyear << " and the population is now " << pop_at_start_of_period << ".\n";
}

void birthdeathrate(){
double increase = births-deaths;
popgrowth = pop_at_start_of_period-increase*100;
}

void population(){
double k = popgrowth/100;
double kt = k*t;
double e = 2.71828183;

double P = pop_at_start_of_period*pow(e,kt);

cout << P;

pop_at_start_of_period = P;
}

void otherfactors(){
births = 50;
deaths = 20; // will be more complex when taking other variables into account.
}

[/code]


What is it that I'm doing wrong?
Thanks.

Oh and I don't really understand this:
[quote][color="#1C2837"][size="2"]std::pow(e,x) == std::exp(x)[/size][/color][/quote]

Share this post


Link to post
Share on other sites
[quote name='White Dwarf' timestamp='1302778998' post='4798337']
What is it that I'm doing wrong?
Thanks.

Oh and I don't really understand this:
[quote]std::pow(e,x) == std::exp(x)[/quote]
[/quote]

If you haven't yet practised with a debugger. I suggest you give it a go. That'd really help you out in this situation. I'll compile your code in a bit and see if I can see what's wrong with it. I probably overlooked something when I was posting late last night.

Alvaro was just saying you can replace:
[code]
pow(e,kt)
[/code]
With:
[code]
exp(kt)
[/code]

It does the same thing, just simpler because you can remove the e variable from your code. It's a minor point, I'd just forgotten that the function existed. I'll get back to you once I've had a play with your code.

EDIT:

So, I had a play around with it and it does actually seem to be working. The population just grows towards zero. It turns out that this line is turning your k value negative which shouldn't happen for a population growth:
[code]
popgrowth = pop_at_start_of_period-increase*100;
[/code]

Did you get your order of precedence right? Should it not have been this?
[code]
popgrowth = (pop_at_start_of_period-increase)*100;
[/code]

Even so, your population grows very very quickly. If you try that line above without the *100 on the end and put in 0.1 as the number of years you want to skip you should see it working :)

Share this post


Link to post
Share on other sites
win_crook, on 14 April 2011 - 01:23 PM, said:
EDIT:

So, I had a play around with it and it does actually seem to be working. The population just grows towards zero. It turns out that this line is turning your k value negative which shouldn't happen for a population growth:
popgrowth = pop_at_start_of_period-increase*100;


Did you get your order of precedence right? Should it not have been this?
popgrowth = (pop_at_start_of_period-increase)*100;


Even so, your population grows very very quickly. If you try that line above without the *100 on the end and put in 0.1 as the number of years you want to skip you should see it working



Okay so I changed the code as you suggested:
[code]
 popgrowth=(pop_at_start_of_period-increase);
[/code]
and entered 0.1 as the amount of years to be skipped and it produced the result: 2637. This seemed too rapid, so I experimented abit and the following code yielded results which were more similar to what I expected.
[code]
popgrowth=(pop_at_start_of_period-increase)*0.01
[/code]
when entering 1 as the amount of years to be skipped the result was: 1101. However when I entered a year increment of more than 71 I would get: 1.079232e+006 (for 72) or something similar.
When I reshuffled to code as such:
[code]

void timestepfoward(){
cout << "\n\nIt is currently year " << currentyear << " and the population is " << pop_at_start_of_periodint << ".\n";
cout << "How many years would you like to skip? ";
cin >> t;
t=t/100;
birthdeathrate();
population();
currentyear = t+currentyear;
cout << "\nIt is now year " << currentyear << " and the population is now " << pop_at_start_of_periodint << ".\n"
}
void birthdeathrate(){
double increase = births-deaths;
popgrowth = (pop_at_start_of_periodint-increase);
}
[/code]
It yielded the same results as the previous code.

Assuming this code is correct, how can I avoid the result being a number like this 1.079232e+006.
Assuming it is incorrect, where have I gone wrong and what can I do to put it right.

Thanks in advance.

Share this post


Link to post
Share on other sites
Your problem is that for a fixed growth rate r = births - deaths, if r > 0 the system explodes (diverges at t = infinity). If r < 0 then the system dies (converges to 0 at t = infinity).

To make the system stable you need to model as a differential equation.

Consider a population with initial population p_0, and every year there are r births and k% of the population dies.

Our differential equation is p' = r - kp.

The solution to this system with initial condition p(0) = p_0 is

p(t) = r/k + (p_0 - r/k)*exp(-kt)

This system is stable and for any initial condition p_0 will converge to p(infinity) = r/k.

Share this post


Link to post
Share on other sites
[quote name='jperalta' timestamp='1302882440' post='4798812']
Your problem is that for a fixed growth rate r = births - deaths, if r > 0 the system explodes (diverges at t = infinity). If r < 0 then the system dies (converges to 0 at t = infinity).

To make the system stable you need to model as a differential equation.

Consider a population with initial population p_0, and every year there are r births and k% of the population dies.

Our differential equation is p' = r - kp.

The solution to this system with initial condition p(0) = p_0 is

p(t) = r/k + (p_0 - r/k)*exp(-kt)

This system is stable and for any initial condition p_0 will converge to p(infinity) = r/k.
[/quote]

Hey jper, I don't really understand what you mean by p_0. It would be great if you could represent this formula in terms of my code:
[code]

void timestepfoward(){
cout << "\n\nIt is currently year " << currentyear << " and the population is " << pop_at_start_of_periodint << ".\n";
cout << "How many years would you like to skip? ";
cin >> t;
birthdeathrate();
population();
currentyear = t+currentyear;
cout << "\nIt is now year " << currentyear << " and the population is now " << pop_at_start_of_periodint << ".\n";
}

void birthdeathrate(){
double increase = births-deaths;
popgrowth = (pop_at_start_of_periodint-increase)*0.01;
}

void population(){
double k = popgrowth/100;
double kt = k*t;

double P = pop_at_start_of_periodint*exp(kt);

int pint = P;
pop_at_start_of_periodint = pint;
}


void otherfactors(){
births = 50;
deaths = 20; // will be more complex when taking other variables into account.
}
[/code]


Many thanks.

Share this post


Link to post
Share on other sites
[font="Arial"]p_0 is your population at time = 0, from your code it looks like you call it 'pop_at_start_of_periodint'.

So what I would do is remove the birthdeathrate() function and change your population() function to look like...

double r = constant population increase per year (for example 1000 births per year)
double k = percentage of population killed per year (for example 0.30 -> 30% of the population dies every year)

then double P = (r/k) + [/font](pop_at_start_of_periodint- (r/k)) *exp(-k*t)

should give you a stable system.

Share this post


Link to post
Share on other sites
[quote name='jperalta' timestamp='1302997700' post='4799312']
[font="Arial"]p_0 is your population at time = 0, from your code it looks like you call it 'pop_at_start_of_periodint'.

So what I would do is remove the birthdeathrate() function and change your population() function to look like...

double r = constant population increase per year (for example 1000 births per year)
double k = percentage of population killed per year (for example 0.30 -> 30% of the population dies every year)

then double P = (r/k) + [/font](pop_at_start_of_periodint- (r/k)) *exp(-k*t)

should give you a stable system.
[/quote]


It now reaches 2500 population, then stops, no matter how high the time value is. Argh so frustrating...
Current code:
[code]
void timestepfoward(){
cout << "\n\nIt is currently year " << currentyear << " and the population is " << pop_at_start_of_periodint << ".\n";
cout << "How many years would you like to skip? ";
cin >> t;
population();
currentyear = t+currentyear;
cout << "\nIt is now year " << currentyear << " and the population is now " << pop_at_start_of_periodint << ".\n";
}


void population(){
double k = (deaths/pop_at_start_of_periodint);

double P = (births/k)+(pop_at_start_of_periodint-(births/k))*exp(-k*t);

int pint = P;
pop_at_start_of_periodint = pint;
}

void otherfactors(){
births = 50;
deaths = 20; // will be more complex when taking other variables into account.
}[/code]

Share this post


Link to post
Share on other sites
White Dwarf. I commend your research. If you want any advice or help regarding this subject, please private message me. That said, please don't take the following comment personally...

Does everyone remember that thread from a few months ago about whether or not First Nations people would have ever "advanced" if Europeans hadn't come to the Americas?

Remember how I said it was nonsense, because First Nations people knew the logistic function like the back of their hand even though they didn't have the symbolic language to describe it?

You guys are nothing but a bunch of fancy rabbits with oversized egos. Have fun trying to figure this out! Bwahaha.

Share this post


Link to post
Share on other sites
Well, first, k should not be a function of population. It should be a constant. It is the fraction of the population that dies every year. Say 1/10 people in the model die every year, then k = 0.1, not 0.1 * current population. Second, if we look at our equation for population as a function of time...

p(t) = (r/k) - (P_0 - (r/k))*exp(-k*t)

we see that the lim t->infinity p(t) = r/k, because the second term will go to zero. This means that if your constant birth rate is 1,000 births per year and your death rate is 10% then the population for any sufficiently large value of t will be near to 10,000 people.

Share this post


Link to post
Share on other sites
[quote name='jperalta' timestamp='1303216308' post='4800325']
Well, first, k should not be a function of population. It should be a constant. It is the fraction of the population that dies every year. Say 1/10 people in the model die every year, then k = 0.1, not 0.1 * current population. Second, if we look at our equation for population as a function of time...

p(t) = (r/k) - (P_0 - (r/k))*exp(-k*t)

we see that the lim t->infinity p(t) = r/k, because the second term will go to zero. This means that if your constant birth rate is 1,000 births per year and your death rate is 10% then the population for any sufficiently large value of t will be near to 10,000 people.
[/quote]

I commend your efforts too, which is why I rated you ++ up the wazoo. Good work man. You sir are a fancy rabbit with a normal sized ego. That's rare.

That said, I still find it highly disappointing that no one mentioned Malthus or Verhulst or Volterra or the logistic function once in this thread. Armed with that information, White Dwarf may now feel free to investigate the meaning of the parameters on their own, to verify/discredit what you are saying:

K represents what is known as the [url="http://en.wikipedia.org/wiki/Carrying_capacity"]carrying capacity[/url] in all official documentation on the subject.

I wonder where all the self-declared experts from the AI board are? They use the logistic function as an activation function all the time, so this should have been a cakewalk for them. Perhaps they're still busy trying to figure out that people use Greek characters for constants in their manuscripts because it's an homage to the Greeks, and not a sign of elitism.

Share this post


Link to post
Share on other sites
[quote name='taby' timestamp='1303220997' post='4800355']
I wonder where all the self-declared experts from the AI board are? They use the logistic function as an activation function all the time, so this should have been a cakewalk for them. Perhaps they're still busy trying to figure out that people use Greek characters for constants in their manuscripts because it's an homage to the Greeks, and not a sign of elitism.
[/quote]
Please drop the attitude and try to stay on-topic -- posts like this achieve nothing other than potentially dragging the discussion off-topic. You can consider this an official warning. Should you wish to discuss the matter with me further please feel welcome to do so via private message rather than cluttering up the topic more.

Share this post


Link to post
Share on other sites
I'm sorry but even with my best attempts at all the suggested solutions I still can't get a working formula. If anyone could muster up some working code for this I would be eternally grateful as it is really preventing me from moving on with the program.

Thanks in advance.

-EDIT:

This

[code]


int main()
{
double initpop=1000;
double births=24;
double deaths=19;
double birthdeathrate=(births-deaths)/initpop+1;
unsigned int population;
int t;


cout << "Enter year increment: ";
cin >> t;

population = initpop*(pow(birthdeathrate,t));

cout << population;
}
[/code]



works fine for me.

Share this post


Link to post
Share on other sites
Your form is close. I added the exponential growth formula to your code, its the one that prints 2nd.

Notice the difference when you input something like 500 years (and then work each formula with that t value to see why its different)
[quote]
Enter year increment: 500
12106
12182
[/quote]
Your form does something like this (using the provided values in your code)
1.005 to the power of t (number of years) multiplied by the initial population equals the new population.

The exponential form does the following.
Initial population multiplied by: 'e' to the power of (0.005 * t) equals the new population.

I think your form is more intuitive, but since everything else uses newPop=initPop*e^(rate*time), I suggest that you use that.

The 0.005 is your 'k' value above. It represents a percent as a decimal, that is 1% is the number 0.01. Your (birth-death)/initpop results in (24-19)/1000 = 0.005 so this is your k value, a population increase of 0.5% per year (t).

Google up "Exponential Growth" to see more detail about it. This formula is used often enough that it is pretty handy to have memorized and understood.

[code]

int main(void)
{
double initpop=1000;
double births=24;
double deaths=19;
double birthdeathrate=(births-deaths)/initpop+1;
unsigned int population;
int t;


cout << "Enter year increment: ";
cin >> t;

population = initpop*(pow(birthdeathrate,t));

cout << population << endl;

population = initpop*exp( (births-deaths)/initpop * t );

cout << population << endl;

return 0;
}

[/code]

Hope this helps!

Share this post


Link to post
Share on other sites
By the way, you can solve for k or t if you know both the initialPopulation and newPopulation along with one or the other of k or t.

k = ln( newPopulation / initialPopulation ) / t;

t = ln( newPopulation / initialPopulation ) / k;

The function "ln(...)" is in the C++ header <cmath>.

If the initial population is 6 billion, and we wonder [b]how long it will take[/b] to reach 15 billion at a growth rate of 1.2% then we are solving for t.
t = ln ( 15,000,000,000 / 6,000,000,000 ) / 0.012
t = ln ( 2.5 ) / 0.012
t = 0.91629... / 0.012
t = 76.358 years

If the initial population is 6 billion, and someone tells us that it will be 10 billion 50 years from now, what is the growth rate? Solving for k.
k = ln ( 10,000,000,000 / 6,000,000,000 ) / 50
k = ln ( 1.666~ ) / 50
k = 0.5108... / 50
k = 0.0102
The growth rate would be 1.02%.

Share this post


Link to post
Share on other sites
[quote name='mozie' timestamp='1303745243' post='4802682']
Your form is close. I added the exponential growth formula to your code, its the one that prints 2nd.

Notice the difference when you input something like 500 years (and then work each formula with that t value to see why its different)
[quote]
Enter year increment: 500
12106
12182
[/quote]
Your form does something like this (using the provided values in your code)
1.005 to the power of t (number of years) multiplied by the initial population equals the new population.

The exponential form does the following.
Initial population multiplied by: 'e' to the power of (0.005 * t) equals the new population.

I think your form is more intuitive, but since everything else uses newPop=initPop*e^(rate*time), I suggest that you use that.

The 0.005 is your 'k' value above. It represents a percent as a decimal, that is 1% is the number 0.01. Your (birth-death)/initpop results in (24-19)/1000 = 0.005 so this is your k value, a population increase of 0.5% per year (t).

Google up "Exponential Growth" to see more detail about it. This formula is used often enough that it is pretty handy to have memorized and understood.

[code]

int main(void)
{
double initpop=1000;
double births=24;
double deaths=19;
double birthdeathrate=(births-deaths)/initpop+1;
unsigned int population;
int t;


cout << "Enter year increment: ";
cin >> t;

population = initpop*(pow(birthdeathrate,t));

cout << population << endl;

population = initpop*exp( (births-deaths)/initpop * t );

cout << population << endl;

return 0;
}

[/code]


Hope this helps!
[/quote]



Thank you, this was the exact explanation I was hoping to receive. Perfectly explained, helpful and accurate. And thanks for elaborating on the rearranging of the formula, it helped me understand better and should come in handy when completing this program. +rep [img]http://public.gamedev.net/public/style_emoticons/default/biggrin.gif[/img]

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this