Skip to content

Instantly share code, notes, and snippets.

@TheBuzzSaw
Last active May 9, 2017 15:31
Show Gist options
  • Select an option

  • Save TheBuzzSaw/5f04865e6e514dfefccd9150ffd3e474 to your computer and use it in GitHub Desktop.

Select an option

Save TheBuzzSaw/5f04865e6e514dfefccd9150ffd3e474 to your computer and use it in GitHub Desktop.
MONEYZ
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <algorithm>
#include <cstdint>
using namespace std;
struct Money
{
int64_t cents;
inline Money& operator+=(Money m)
{
cents += m.cents;
return *this;
}
inline Money& operator-=(Money m)
{
cents -= m.cents;
return *this;
}
inline Money& operator*=(int64_t multiplier)
{
cents *= multiplier;
return *this;
}
inline Money& operator/=(int64_t divisor)
{
cents /= divisor;
return *this;
}
};
constexpr Money operator-(Money money)
{
return {-money.cents};
}
constexpr Money operator+(Money a, Money b)
{
return {a.cents + b.cents};
}
constexpr Money operator-(Money a, Money b)
{
return {a.cents - b.cents};
}
constexpr Money operator*(Money a, int64_t b)
{
return {a.cents * b};
}
constexpr Money operator/(Money a, int64_t b)
{
return {a.cents / b};
}
constexpr bool operator==(Money a, Money b)
{
return a.cents == b.cents;
}
constexpr bool operator!=(Money a, Money b)
{
return a.cents != b.cents;
}
constexpr bool operator<(Money a, Money b)
{
return a.cents < b.cents;
}
constexpr bool operator<=(Money a, Money b)
{
return a.cents <= b.cents;
}
constexpr bool operator>(Money a, Money b)
{
return a.cents > b.cents;
}
constexpr bool operator>=(Money a, Money b)
{
return a.cents >= b.cents;
}
ostream& operator<<(ostream& stream, Money money)
{
uint64_t cents = money.cents;
if (money.cents < 0)
{
stream << '-';
cents = -money.cents;
}
uint64_t dollars = cents / 100;
cents -= dollars * 100;
stream << dollars << '.';
if (cents < 10) stream << '0';
return stream << cents;
}
struct Loan
{
Money principal;
int64_t interest; // 1 = 0.01%
Money minPayment;
};
void RunSimulation(vector<Loan> loans, Money monthlyIncome)
{
static int fileId = 0;
stringstream ss;
ss << "loan_" << ++fileId << ".txt";
ofstream fout(ss.str(), ofstream::binary);
int monthCount = 0;
Money totalPaid{0};
Money minMonthlyIncome{0};
for (auto loan : loans) minMonthlyIncome += loan.minPayment;
if (monthlyIncome < minMonthlyIncome)
{
//cout << '$' << monthlyIncome << " is not enough. Minimum income is $" << minMonthlyIncome << ".\n";
monthlyIncome = minMonthlyIncome;
}
bool keepPaying = true;
int n = 0;
Money lastExcess{0};
Money excess{0};
Money totalInterest{0};
while (keepPaying)
{
auto income = monthlyIncome;
// Pay minimum amounts.
fout << "\nMonth " << ++monthCount << " ($" << income << ")" << '\n';
for (auto& loan : loans)
{
if (loan.principal.cents < 1) continue;
fout << "principal $" << loan.principal << " min $" << loan.minPayment;
loan.principal -= loan.minPayment;
income -= loan.minPayment;
totalPaid += loan.minPayment;
if (loan.principal.cents < 0)
{
income -= loan.principal;
totalPaid += loan.principal;
loan.principal = {0};
}
fout << " new principal $" << loan.principal << '\n';
}
// Apply excess.
fout << "--- excess funds: $" << income << '\n';
if (income > lastExcess)
{
lastExcess = income;
fout << "--- increased cash flow\n";
}
excess += income;
for (auto& loan : loans)
{
if (loan.principal.cents < 1)
continue;
else if (income.cents < 1)
break;
fout << "principal $" << loan.principal << " excess $" << income;
loan.principal -= income;
totalPaid += income;
income = {0};
if (loan.principal.cents < 0)
{
income -= loan.principal;
totalPaid += loan.principal;
loan.principal = {0};
}
fout << " new principal $" << loan.principal << '\n';
}
// Apply interest.
fout << "--- accrue interest\n";
keepPaying = false;
for (auto& loan : loans)
{
if (loan.principal.cents < 1) continue;
auto interest = loan.principal * loan.interest / 120000;
totalInterest += interest;
fout << "principal $" << loan.principal << " interest $" << interest;
keepPaying |= loan.principal.cents > 0;
loan.principal += interest;
fout << " new principal $" << loan.principal << '\n';
}
}
cout << "paid $" << totalPaid << " ($" << totalInterest << " in interest) over "
<< monthCount << " months with an average cash flow of $" << (excess / monthCount) << " \n";
fout.close();
}
bool AvalancheSort(const Loan& a, const Loan& b)
{
return a.interest > b.interest ||
(a.interest == b.interest && a.principal < b.principal);
}
bool SnowballSort(const Loan& a, const Loan& b)
{
return a.principal < b.principal ||
(a.principal == b.principal && a.interest > b.interest);
}
int main(int argc, char** argv)
{
vector<Loan> loans;
//loans.push_back({{2000000}, 800, {19113}});
//loans.push_back({{200000}, 800, {4055}});
//loans.push_back({{500000}, 1800, {12697}});
loans.push_back({{897357}, 825, {10500}});
loans.push_back({{176190}, 240, {11500}});
loans.push_back({{32840}, 443, {2400}});
loans.push_back({{841479}, 443, {6100}});
loans.push_back({{1059859}, 510, {8000}});
loans.push_back({{3657792}, 825, {34500}});
sort(loans.begin(), loans.end(), AvalancheSort);
cout << "Avalanche\n";
RunSimulation(loans, {103000});
sort(loans.begin(), loans.end(), SnowballSort);
cout << "Snowball\n";
RunSimulation(loans, {103000});
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment