Напишите программу для расчета баланса кредитной карты через год, если человек платит только минимальный ежемесячный платеж, требуемый компанией-эмитентом кредитной карты каждый месяц.
Следующие переменные содержат значения, как описано ниже:
balance
— непогашенный остаток по кредитной карте
annualInterestRate
— годовая процентная ставка в виде десятичной дроби
monthlyPaymentRate
— минимальная ежемесячная ставка платежа в виде десятичной дробиЗа каждый месяц рассчитывайте выписки по ежемесячному платежу и остатку. По истечении 12 месяцев распечатайте остаток. Обязательно распечатайте не более двух десятичных знаков точности — так что печатайте
Remaining balance: 813.41
вместо
Remaining balance: 813.4141998135
Таким образом, ваша программа выводит только одно: остаток на конец года в формате:
Remaining balance: 4784.0
Краткое изложение требуемой математики можно найти ниже:
begin {align *} text {Ежемесячная процентная ставка} & = frac { text {Годовая процентная ставка}} {12} \ text {Минимальный ежемесячный платеж} & = text {Минимальная ежемесячная ставка платежа} times text {Предыдущий остаток} \ text {Ежемесячный невыплаченный остаток} & = text {Предыдущий остаток} \ & — text {Минимальный ежемесячный платеж} \ text {Обновляемый остаток каждый месяц} & = text {Ежемесячно невыплаченный остаток} \ & + ( text {Ежемесячная процентная ставка} times text {Ежемесячный невыплаченный остаток}) end {align *}
Код
def balances(initial_balance, annual_interest_rate, minimum_monthly_payment_rate):
balance = initial_balance
monthly_interest_rate = annual_interest_rate / 12
for month in range(13):
minimum_monthly_payment = balance * minimum_monthly_payment_rate
monthly_unpaid_balance = balance - minimum_monthly_payment
yield {'month': month,
'minimum_monthly_payment': minimum_monthly_payment,
'balance': balance}
balance = monthly_unpaid_balance + (monthly_unpaid_balance * monthly_interest_rate)
def main():
*bs, remaining_balance = balances(balance, annualInterestRate, monthlyPaymentRate)
print('Remaining Balance: {}'.format(round(remaining_balance['balance'], 2)))
# Testing data
balance = 484
annualInterestRate = .2
monthlyPaymentRate = .04
## ifname_main does not work in grader
if __name__ == '__main__':
main()
Заранее спасибо.
2 ответа
- Можно использовать подсказки типа PEP484
range(13)
неудобно — нет смысла возвращать начальный баланс, поэтому просто выведите скорректированные остатки и сделайте это 12 раз- Нет смысла сдавать месяц, платеж и баланс; просто уступите баланс. Даже если вам нужно было найти все три, словарь — не лучший способ сделать это. Кортежи стандартные; или класс данных лучше структурирован.
- Не надо звонить
format
или жеround
. Просто используйте.2f
. Обратите внимание, что это противоречит спецификацииRemaining balance: 4784.0
но это глупо; это денежная сумма, поэтому точность должна быть фиксированной. - Ваш
balances
хорош как генератор, но зачем ограничивать его до 12 итераций? Более общая и полезная реализация просто повторяется бесконечно. Использоватьislice
вывести 12 значений, игнорируя все, кроме последнего.
Предлагаемый (итеративный)
from itertools import islice
from typing import Iterable
def balances(
initial_balance: float,
annual_interest_rate: float,
minimum_monthly_payment_rate: float,
) -> Iterable[float]:
balance = initial_balance
monthly_interest_rate = annual_interest_rate / 12
while True:
minimum_monthly_payment = balance * minimum_monthly_payment_rate
monthly_unpaid_balance = balance - minimum_monthly_payment
balance = monthly_unpaid_balance * (1 + monthly_interest_rate)
yield balance
def main():
for balance in islice(
balances(
initial_balance=484.00,
annual_interest_rate=0.20,
minimum_monthly_payment_rate=0.04,
),
12,
):
pass
print(f'Remaining Balance: {balance:.2f}')
if __name__ == '__main__':
main()
Упрощение внутреннего цикла заменило бы его на
balance *= (1 - minimum_monthly_payment_rate) * (1 + monthly_interest_rate)
что эквивалентно.
Предлагаемый (составной)
Еще лучше полностью избавиться от цикла и просто использовать мощность:
def compound(
initial_balance: float,
annual_interest_rate: float,
minimum_monthly_payment_rate: float,
months: int,
) -> float:
monthly_interest_rate = annual_interest_rate / 12
return initial_balance * (
(1 - minimum_monthly_payment_rate) * (1 + monthly_interest_rate)
) ** months
def main():
balance = compound(
initial_balance=484.00,
annual_interest_rate=0.20,
minimum_monthly_payment_rate=0.04,
months=12,
)
print(f'Remaining Balance: {balance:.2f}')
if __name__ == '__main__':
main()
В balances
функция немного длинная. Содержимое цикла может быть другой функцией. Эта функция отвечает за выполнение этого требования:
За каждый месяц рассчитывайте выписки по ежемесячному платежу и остатку
Вместо yield
-создание конструкции с month
, minimum_monthly_payment
, а также balance
для каждой итерации цикла вы можете return
в конце петли. Фактически, month
а также minimum_monthly_payment
не используется вообще, поэтому вы можете вернуть только оставшиеся balance
в конце 12 месяцев.
Поскольку balances
функция теперь возвращает только одно число, вы можете избавиться от сложного кода на main
. Просто возьмите этот номер и распечатайте его.
После этих изменений переименуйте balances
метод к чему-то более значимому.
Разве не было бы бесполезно давать отрицательный баланс? Может быть, сделай это
while balance >= 0
— РэкетирHaskeller
Возможный. Добавьте это, если хотите. Существуют некоторые типы счетов (без кредитных карт), для которых было бы полезно иметь возможность отображать как кредитное, так и дебетовое состояние.
— Райндериен
Тем не менее, сделайте небольшую математику, и вы обнаружите, что баланс никогда не опускается до нуля или ниже нуля за конечное количество итераций.
— Райндериен