Interest is compounded monthly. Payment doesn't  vary from month to month.Version 1balance = 999999annualInterestRate = 0.18mRate = annualInterestRate/12high = (((mRate+1)**12)*balance)/12low = balance/12guessed = Falsedef balanceLeft(balance,mRate,minPayment):    monthsLeft = 12    while monthsLeft > 0:        unpaidBalance =  balance - minPayment        interest = mRate * unpaidBalance        balance = unpaidBalance        balance += interest        monthsLeft -= 1    return balancewhile guessed == False:    minPayment = (high + low) / 2    if round(balanceLeft(balance,mRate,minPayment),2) < 0:        high = minPayment    elif round(balanceLeft(balance,mRate,minPayment),2)> 0:        low = minPayment    else:        if abs(round(balanceLeft(balance,mRate,minPayment),2) - 0) < 0.01:            guessed = Trueprint('Lowest Payment: ',end='')print(round(minPayment,2))Version 2annualInterestRate = 0.18rate = annualInterestRate / 12monthsLeftr = 12xCoefficent = 1 + rateConstantTerm = 1 + ratewhile monthsLeftr > 1:    xCoefficent = (xCoefficent + 1) * ConstantTerm    monthsLeftr -= 1balance = 999999monthsLeft = 12while monthsLeft > 0:    balance = balance * ConstantTerm    monthsLeft -= 1minPayment = balance / xCoefficentprint('Lowest Payment: ', end=)I would like a comparative and overall review, please!
For a given balance and an annual interest rate, calculate the minimum fixed monthly payment to pay off debt in a year
python;python 3.x;comparative review;calculator;finance
General commentsuse a consistent style: space after a comma, or not; spaces around operators, or not; even two spaces sometimes. Python has an official style guide called PEP 8 which is worth a read, youll understand why the syntax highlight here is colouring ConstantTerm in light blue.use functions to parametrize values. As it stand it is impossible to reuse any of that code to perform computations with other rates, initial lending, or even various number of years.use the if __name__ == '__main__': clause to wrap your top-level code.use a for loop to perform the same computation a given number of time. e.g.:for _ in range(monthsLeft):    balance = balance * ConstantTermuse constants for magic numbers: MONTHS_IN_A_YEAR = 12A first and quick rewrite could be:MONTHS_IN_A_YEAR = 12def balance_left(balance, monthly_rate, monthly_payment):    for _ in range(MONTHS_IN_A_YEAR):        unpaid_balance =  balance - monthly_payment        interest = monthly_rate * unpaid_balance        balance = unpaid_balance        balance += interest    return balancedef minimal_monthly_payment(balance, annual_interests):    monthly_rate = annual_interest / MONTHS_IN_A_YEAR    lower_bound = balance / MONTHS_IN_A_YEAR    higher_bound = (monthly_rate + 1)**MONTHS_IN_A_YEAR * lower_bound    guessed = False    while not guessed:        monthly_payment = (higher_bound + lower_bound) / 2        yearly_balance = balance_left(balance, monthly_rate, monthly_payment)        rounded_balance = round(yearly_balance, 2)        if rounded_balance < 0:            higher_bound = monthly_payment        elif rounded_balance > 0:            lower_bound = monthly_payment        else:            if abs(rounded_balance - 0) < 0.01:                guessed = True    return monthly_paymentif __name__ == '__main__':    minimal_cost = minimal_monthly_payment(999999, 0.18)    print('Lowest Payment:', round(minimal_cost, 2))MONTHS_IN_A_YEAR = 12def annual_rate_coefficient(monthly_interests_rate):    coefficient = monthly_interests_rate    for _ in range(MONTHS_IN_A_YEAR - 1):        coefficient = (coefficient + 1) * monthly_interests_ratedef minimal_monthly_payment(balance, annual_interests):    monthly_interests_rate = 1 + annual_interests / MONTHS_IN_A_YEAR    for _ in range(MONTHS_IN_A_YEAR):        balance = balance * monthly_interests_rate    return = balance / annual_rate_coefficient(monthly_interests_rate)if __name__ == '__main__':    minimal_cost = minimal_monthly_payment(999999, 0.18)    print('Lowest Payment:', round(minimal_cost, 2))Version 1You can rearange the maths in balance_left to make it more efficient:balance = unpaid_balancebalance += interestis equivalent tobalance = unpaid_balance + interestis equivalent tobalance = unpaid_balance + monthly_rate * unpaid_balanceis equivalent tobalance = unpaid_balance * (monthly_rate + 1)is equivalent tobalance = (balance - monthly_payment) * (monthly_rate + 1)so:def balance_left(balance, monthly_rate, monthly_payment):    monthly_interests_rate = 1 + monthly_rate    for _ in range(MONTHS_IN_A_YEAR):        balance = (balance - monthly_payment) * monthly_interests_rate    return balanceYou can also simplify minimal_monthly_payment:you can use an infinite loop and return from it instead of using a flag;you don't need the test if abs() < 0.01 because you know from the previous if and elif that rounded_balance is neither > 0 nor < 0. So rounded_balance is 0 and you have found your minimal monthly payment.def minimal_monthly_payment(balance, annual_interests):    monthly_rate = annual_interest / MONTHS_IN_A_YEAR    lower_bound = balance / MONTHS_IN_A_YEAR    higher_bound = (monthly_rate + 1)**MONTHS_IN_A_YEAR * lower_bound    while True:        monthly_payment = (higher_bound + lower_bound) / 2        yearly_balance = balance_left(balance, monthly_rate, monthly_payment)        rounded_balance = round(yearly_balance, 2)        if rounded_balance < 0:            higher_bound = monthly_payment        elif rounded_balance > 0:            lower_bound = monthly_payment        else:            return monthly_paymentVersion 2I find this version more interesting because the algorithm is more efficient. The computation is straightforward and doesn't compute intermediate results that are only a mean to tighten the bounds.It may benefit from using comments to explain why this approach is computing the right result.Anyway, we can still improve it: it uses 2 for loops that are almost the same. Can't we make it both be for _ in range(MONTHS_IN_A_YEAR): and merge them? I will necessitate to integrate coefficient = monthly_interests_rate into the loop. Luckyly, (0 + 1) * monthly_interests_rate is monthly_interests_rate:def annual_rate_coefficient(monthly_interests_rate):    coefficient = 0    for _ in range(MONTHS_IN_A_YEAR):        coefficient = (coefficient + 1) * monthly_interests_rateso now we can merge both loops:MONTHS_IN_A_YEAR = 12def minimal_monthly_payment(balance, annual_interests):    monthly_interests_rate = 1 + annual_interests / MONTHS_IN_A_YEAR    coefficient = 0    for _ in range(MONTHS_IN_A_YEAR):        coefficient = (coefficient + 1) * monthly_interests_rate        balance = balance * monthly_interests_rate    return = balance / coefficientif __name__ == '__main__':    minimal_cost = minimal_monthly_payment(999999, 0.18)    print('Lowest Payment:', round(minimal_cost, 2))Going furtherDefining minimal_monthly_payment as a function will allow you to import it in an interactive shell and test it with various amounts and rates. But you could also integrate a command-line parser so you could call your script like:python <module_name>.py 999999 0.18You can try to manually take the content from sys.argv and convert it, or let a specialyzed module do the job. For instance argparse:if __name__ == '__main__':    import argparse    parser = argparse.ArgumentParser(description='Minimal monthly payment calculator')    parser.add_argument('balance', type=int, help='initial lending')    parser.add_argument('rate', type=float, help='annual interests rate')    args = parser.parse_args()    minimal_cost = minimal_monthly_payment(args.balance, args.rate)    print('Lowest Payment:', round(minimal_cost, 2))