Last active
May 9, 2017 15:31
-
-
Save TheBuzzSaw/5f04865e6e514dfefccd9150ffd3e474 to your computer and use it in GitHub Desktop.
MONEYZ
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #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