Interest and Logic
One of the logic problems in programming that most break the head of those who are starting are the problems with percentage calculation or interest.
It starts like this: Calculate 10% increase on a salary of $2,500.00
Depending on the student’s math background, percentage is learned in 4th/5th grade… some concepts need to be remembered. As the name says, 10% means that for every 100 of the value, you should subtract 10. The calculation is quite simple and can be done with a multiplication. For example: 10/100 * 2500, which results in 250. So far so good, but some students ask why sometimes we do 0.1 * 2500. Well, it’s just the way of representation that changes, because 10/100 is equivalent to 0.1, alias 100/1000 also and so on. But this is the easy part and after getting the notation right, things start working again.
When we get to repetitions, problems like savings calculation begin to appear. They have the following format: imagine someone deposits $1,000.00 in a savings account that earns 1% per month (good times). After n months, how much will the person have as a balance? The problem combines percentage with repetition. Let’s see what it looks like for 6 months:
saldo = 1000 # Initial value
n = 6 # Number of months
juros = 0.01 # Monthly interest 1% = 1/100 = 0.01
for mês in range(1, n + 1):
saldo *= 1 + juros
print(f"Month ({mês}): {saldo:7.2f}")
which results in:
Month (1): 1010.00
Month (2): 1020.10
Month (3): 1030.30
Month (4): 1040.60
Month (5): 1051.01
Month (6): 1061.52
Many questions arise.
Why *=
?#
It’s because the interest is compound, or rather applied to the previous balance. It doesn’t calculate 1% of the initial salary and multiply it by the number of months. It will become clearer later with the formula.
Why do we add 1 to the interest?#
As we are multiplying the balance, we need to adjust the new balance so that it is equal to the previous one plus the interest for the month. In a longer format it would be saldo = saldo + juros * saldo
. This calculation can be simplified by grouping the variable saldo in such a way that saldo = saldo * (1 + juros)
. As in Python we can write saldo = saldo *
as saldo *=
, the expression becomes: saldo *= (1 + juros)
, note that I removed the parentheses since they are no longer necessary.
Do we need repetition to perform this calculation?#
No, you can have an analytical solution, applying the formula: `saldo = saldo * (1 + juros) ** mês).
Example:
>>> print(f"{1000 * (1 + 0.01) ** 6:7.2f}")
1061.52
Where does this exponentiation come from?#
If we go back to the example with repetition, we will see that:
In month 1, the balance is saldo * 1.01.
The balance in month 2 is saldo * 1.01 * 1.01
In month 3, saldo * 1.01 * 1.01 * 1.01
And so on, we start to see a pattern where 1.01 is multiplied by itself the number of months we are calculating. We can then write in general that saldo *= 1.01 ** mês
, which is just the definition of exponentiation: a ** n = a * a * a ... (n times)
Why do we use repetition?#
Because it’s a programming course and the teacher wants you to have a reason to use for or while.
A question that appeared today on Stack Overflow in Portuguese#
The question was voted down and soon closed :-(
Two shoe manufacturers compete in the Brazilian market. Company A has a production of 10,000 pairs/month and a monthly growth rate of 15%. Company B has a production of 8,000 pairs/month and has a monthly growth rate of 20%. Determine the number of months necessary for company B to exceed the number of pairs produced by company A.
Let’s see what it looks like in math:
Production of company A: 10000 x 1.15^m
Production of company B: 8000 x 1.20^m
Where m is the number of months.
What you are looking for is the value of m when:
8000 x 1.20^m > 10000 x 1.15^m
You can solve this using logarithms, but in a programming course, the teacher probably expects you to iterate over the value of m from 1.
So try calculating the production when m = 1. Compare the production of both companies (use the formulas above). If B’s value does not exceed A’s, continue incrementing m by 1. Stop when B’s production is greater than A’s (the answer is the value of m when this happens).
m = 0
while True:
prodA = 10000 * 1.15 ** m
prodB = 8000 * 1.2 ** m
print(f"Prod A: {prodA:8.2f} Prod B: {prodB:8.2f} - month: {m}")
if prodB > prodA:
break
m += 1
print(f"Months for company B to exceed company A's production: {m}")
which results in:
Prod A: 10000.00 Prod B: 8000.00 - month: 0
Prod A: 11500.00 Prod B: 9600.00 - month: 1
Prod A: 13225.00 Prod B: 11520.00 - month: 2
Prod A: 15208.75 Prod B: 13824.00 - month: 3
Prod A: 17490.06 Prod B: 16588.80 - month: 4
Prod A: 20113.57 Prod B: 19906.56 - month: 5
Prod A: 23130.61 Prod B: 23887.87 - month: 6
Months for company B to exceed company A's production: 6
And the analytical solution? As I said, it’s a programming course :-(
But you can solve the inequality using logarithms:
8000 x 1.20^m > 10000 x 1.15^m
ln(8000) + m * ln(1.20) > ln(10000) + m * ln(1.15)
m * ln(1.20) - m * ln(1.15) > ln(10000) - ln(8000)
m * (ln(1.20) - ln(1.15)) > ln(10000) - ln(8000)
m = (ln(10000) - ln(8000))/(ln(1.20) - ln(1.15))
which in Python becomes:
from math import log
m = (log(10000) - log(8000))/(log(1.20) - log(1.15))
print(m)
which results in:
5.243082071149164
Which we can round to 6, assuming we don’t consider fractions of a month. Now we know both the analytical and iterative methods. It’s easy to understand why the second is more used in programming courses.