My project involves creating a table of data with a row for each of the 12 months of the year. The user of the app will define their monthly pay and percentage of pay they want to contribute to his/her 401k. The table shows in which month the user has reached the IRS contribution limit ($22,500) and consequently cannot contribute any more until next year.
I'm using Xcode playground to test my formulae. Since each month from February through December must look back at contributions and sums from the previous months, there is a considerable amount of looping which drives excessive execution time. I have a computed variable titled "personal401kContributionMonthly" which computes what the user has defined for their desired percent of monthly pay to contribute to their 401k. This computed property ran 4,940,531 times before the playground crashed with the following error: "error: Execution was interrupted, reason: signal SIGKILL. [12211:365921] Unable to quarantine process. (Error: -1.)"
I am seeking for advice/techniques to simplify the code to avoid the crash.
var monthlyPay = 15203.0
var personal401kLimit = 22500.0
var personal401kPercentage = 10.0
var roth401kPercentage = 10.0
var personal401kContributionMonthly: Double {
monthlyPay * (personal401kPercentage/100)
}
personal401kContributionMonthly
var persTradContJan: Double {
personal401kContributionMonthly <= personal401kLimit ? (personal401kContributionMonthly * (1 - (roth401kPercentage/100))) : personal401kLimit * (1 - (roth401kPercentage/100))
}
persTradContJan
var persRothContJan: Double {
roth401kPercentage == 0.0 ? 0.0 : personal401kContributionMonthly <= personal401kLimit ? personal401kContributionMonthly * (roth401kPercentage/100) : personal401kLimit * (roth401kPercentage/100)
}
persRothContJan
var pers401ksumFeb: Double {
persTradContJan + persRothContJan
}
var persTradContFeb: Double {
pers401ksumFeb + personal401kContributionMonthly <= personal401kLimit ? personal401kContributionMonthly * (1 - (roth401kPercentage/100)) : pers401ksumFeb < personal401kLimit ? (1 - (roth401kPercentage/100)) * (personal401kLimit - (pers401ksumFeb)) : 0.0
}
persTradContFeb
var persRothContFeb: Double {
roth401kPercentage == 0.0 ? 0.0 : pers401ksumFeb + personal401kContributionMonthly <= personal401kLimit ? personal401kContributionMonthly * (roth401kPercentage/100) : pers401ksumFeb < personal401kLimit ? (roth401kPercentage/100) * (personal401kLimit - pers401ksumFeb) : 0.0
}
persRothContFeb
var pers401ksumMar: Double {
persTradContJan + persRothContJan + persTradContFeb + persRothContFeb
}
var persTradContMar: Double {
pers401ksumMar + personal401kContributionMonthly <= personal401kLimit ? personal401kContributionMonthly * (1 - (roth401kPercentage/100)) : pers401ksumMar < personal401kLimit ? (1 - (roth401kPercentage/100)) * (personal401kLimit - (pers401ksumMar)) : 0.0
}
persTradContMar
var persRothContMar: Double {
roth401kPercentage == 0.0 ? 0.0 : pers401ksumMar + personal401kContributionMonthly <= personal401kLimit ? personal401kContributionMonthly * (roth401kPercentage/100) : pers401ksumMar < personal401kLimit ? (roth401kPercentage/100) * (personal401kLimit - pers401ksumMar) : 0.0
}
persRothContMar
var pers401ksumApr: Double {
persTradContJan + persRothContJan + persTradContFeb + persRothContFeb + persTradContMar + persRothContMar
}
var persTradContApr: Double {
pers401ksumApr + personal401kContributionMonthly <= personal401kLimit ? personal401kContributionMonthly * (1 - (roth401kPercentage/100)) : pers401ksumApr < personal401kLimit ? (1 - (roth401kPercentage/100)) * (personal401kLimit - (pers401ksumApr)) : 0.0
}
persTradContApr
var persRothContApr: Double {
roth401kPercentage == 0.0 ? 0.0 : pers401ksumApr + personal401kContributionMonthly <= personal401kLimit ? personal401kContributionMonthly * (roth401kPercentage/100) : pers401ksumApr < personal401kLimit ? (roth401kPercentage/100) * (personal401kLimit - pers401ksumApr) : 0.0
}
persRothContApr
var pers401ksumMay: Double {
persTradContJan + persRothContJan + persTradContFeb + persRothContFeb + persTradContMar + persRothContMar + persTradContApr + persRothContApr
}
var persTradContMay: Double {
pers401ksumMay + personal401kContributionMonthly <= personal401kLimit ? personal401kContributionMonthly * (1 - (roth401kPercentage/100)) : pers401ksumMay < personal401kLimit ? (1 - (roth401kPercentage/100)) * (personal401kLimit - (pers401ksumMay)) : 0.0
}
persTradContMay
var persRothContMay: Double {
roth401kPercentage == 0.0 ? 0.0 : pers401ksumMay + personal401kContributionMonthly <= personal401kLimit ? personal401kContributionMonthly * (roth401kPercentage/100) : pers401ksumMay < personal401kLimit ? (roth401kPercentage/100) * (personal401kLimit - pers401ksumMay) : 0.0
}
persRothContMay
var pers401ksumJun: Double {
persTradContJan + persRothContJan + persTradContFeb + persRothContFeb + persTradContMar + persRothContMar + persTradContApr + persRothContApr + persTradContMay + persRothContMay
}
var persTradContJun: Double {
pers401ksumJun + personal401kContributionMonthly <= personal401kLimit ? personal401kContributionMonthly * (1 - (roth401kPercentage/100)) : pers401ksumJun < personal401kLimit ? (1 - (roth401kPercentage/100)) * (personal401kLimit - (pers401ksumJun)) : 0.0
}
persTradContJun
var persRothContJun: Double {
roth401kPercentage == 0.0 ? 0.0 : pers401ksumJun + personal401kContributionMonthly <= personal401kLimit ? personal401kContributionMonthly * (roth401kPercentage/100) : pers401ksumJun < personal401kLimit ? (roth401kPercentage/100) * (personal401kLimit - pers401ksumJun) : 0.0
}
persRothContJun
var pers401ksumJul: Double {
persTradContJan + persRothContJan + persTradContFeb + persRothContFeb + persTradContMar + persRothContMar + persTradContApr + persRothContApr + persTradContMay + persRothContMay + persTradContJun + persRothContJun
}
var persTradContJul: Double {
pers401ksumJul + personal401kContributionMonthly <= personal401kLimit ? personal401kContributionMonthly * (1 - (roth401kPercentage/100)) : pers401ksumJul < personal401kLimit ? (1 - (roth401kPercentage/100)) * (personal401kLimit - (pers401ksumJul)) : 0.0
}
persTradContJul
var persRothContJul: Double {
roth401kPercentage == 0.0 ? 0.0 : pers401ksumJul + personal401kContributionMonthly <= personal401kLimit ? personal401kContributionMonthly * (roth401kPercentage/100) : pers401ksumJul < personal401kLimit ? (roth401kPercentage/100) * (personal401kLimit - pers401ksumJul) : 0.0
}
persRothContJul
var pers401ksumAug: Double {
persTradContJan + persRothContJan + persTradContFeb + persRothContFeb + persTradContMar + persRothContMar + persTradContApr + persRothContApr + persTradContMay + persRothContMay + persTradContJun + persRothContJun + persTradContJul + persRothContJul
}
var persTradContAug: Double {
pers401ksumAug + personal401kContributionMonthly <= personal401kLimit ? personal401kContributionMonthly * (1 - (roth401kPercentage/100)) : pers401ksumAug < personal401kLimit ? (1 - (roth401kPercentage/100)) * (personal401kLimit - (pers401ksumAug)) : 0.0
}
persTradContAug
var persRothContAug: Double {
roth401kPercentage == 0.0 ? 0.0 : pers401ksumAug + personal401kContributionMonthly <= personal401kLimit ? personal401kContributionMonthly * (roth401kPercentage/100) : pers401ksumAug < personal401kLimit ? (roth401kPercentage/100) * (personal401kLimit - pers401ksumAug) : 0.0
}
persRothContAug
var pers401ksumSep: Double {
persTradContJan + persRothContJan + persTradContFeb + persRothContFeb + persTradContMar + persRothContMar + persTradContApr + persRothContApr + persTradContMay + persRothContMay + persTradContJun + persRothContJun + persTradContJul + persRothContJul + persTradContAug + persRothContAug
}
var persTradContSep: Double {
pers401ksumSep + personal401kContributionMonthly <= personal401kLimit ? personal401kContributionMonthly * (1 - (roth401kPercentage/100)) : pers401ksumSep < personal401kLimit ? (1 - (roth401kPercentage/100)) * (personal401kLimit - (pers401ksumSep)) : 0.0
}
persTradContSep
var persRothContSep: Double {
roth401kPercentage == 0.0 ? 0.0 : pers401ksumSep + personal401kContributionMonthly <= personal401kLimit ? personal401kContributionMonthly * (roth401kPercentage/100) : pers401ksumSep < personal401kLimit ? (roth401kPercentage/100) * (personal401kLimit - pers401ksumSep) : 0.0
}
persRothContSep
var pers401ksumOct: Double {
persTradContJan + persRothContJan + persTradContFeb + persRothContFeb + persTradContMar + persRothContMar + persTradContApr + persRothContApr + persTradContMay + persRothContMay + persTradContJun + persRothContJun + persTradContJul + persRothContJul + persTradContAug + persRothContAug + persTradContSep + persRothContSep
}
var persTradContOct: Double {
pers401ksumOct + personal401kContributionMonthly <= personal401kLimit ? personal401kContributionMonthly * (1 - (roth401kPercentage/100)) : pers401ksumOct < personal401kLimit ? (1 - (roth401kPercentage/100)) * (personal401kLimit - (pers401ksumOct)) : 0.0
}
persTradContOct
var persRothContOct: Double {
roth401kPercentage == 0.0 ? 0.0 : pers401ksumOct + personal401kContributionMonthly <= personal401kLimit ? personal401kContributionMonthly * (roth401kPercentage/100) : pers401ksumOct < personal401kLimit ? (roth401kPercentage/100) * (personal401kLimit - pers401ksumOct) : 0.0
}
persRothContOct
var pers401ksumNov: Double {
persTradContJan + persRothContJan + persTradContFeb + persRothContFeb + persTradContMar + persRothContMar + persTradContApr + persRothContApr + persTradContMay + persRothContMay + persTradContJun + persRothContJun + persTradContJul + persRothContJul + persTradContAug + persRothContAug + persTradContSep + persRothContSep + persTradContOct + persRothContOct
}
var persTradContNov: Double {
pers401ksumNov + personal401kContributionMonthly <= personal401kLimit ? personal401kContributionMonthly * (1 - (roth401kPercentage/100)) : pers401ksumNov < personal401kLimit ? (1 - (roth401kPercentage/100)) * (personal401kLimit - (pers401ksumNov)) : 0.0
}
persTradContNov
var persRothContNov: Double {
roth401kPercentage == 0.0 ? 0.0 : pers401ksumNov + personal401kContributionMonthly <= personal401kLimit ? personal401kContributionMonthly * (roth401kPercentage/100) : pers401ksumNov < personal401kLimit ? (roth401kPercentage/100) * (personal401kLimit - pers401ksumNov) : 0.0
}
persRothContNov
var pers401ksumDec: Double {
persTradContJan + persRothContJan + persTradContFeb + persRothContFeb + persTradContMar + persRothContMar + persTradContApr + persRothContApr + persTradContMay + persRothContMay + persTradContJun + persRothContJun + persTradContJul + persRothContJul + persTradContAug + persRothContAug + persTradContSep + persRothContSep + persTradContOct + persRothContOct + persTradContNov + persRothContNov
}
var persTradContDec: Double {
pers401ksumDec + personal401kContributionMonthly <= personal401kLimit ? personal401kContributionMonthly * (1 - (roth401kPercentage/100)) : pers401ksumDec < personal401kLimit ? (1 - (roth401kPercentage/100)) * (personal401kLimit - (pers401ksumDec)) : 0.0
}
persTradContDec
var persRothContDec: Double {
roth401kPercentage == 0.0 ? 0.0 : pers401ksumDec + personal401kContributionMonthly <= personal401kLimit ? personal401kContributionMonthly * (roth401kPercentage/100) : pers401ksumDec < personal401kLimit ? (roth401kPercentage/100) * (personal401kLimit - pers401ksumDec) : 0.0
}
persRothContDec
UPDATE 1:
The intent of this 401k project is to also incorporate employer direct contributions and "back-door-Roth" overflow into a 401a account. Consequently I believe I will need to store and initialize the sum of contributions month-to-month because this running total will need to be referenced for calculating each month's 401a contributions.
For example, some employers offer the "back-door" option which allows an employee who has reached the individual contribution limit ($22,500) to continue contributing that year but those funds are deposited into a 401a (not 401k). But once the sum total of a) personal contributions, b) company contributions (match or direct deposit) and c) 401a "back-door" contributions reach the IRS limit for combined contributions ($66,000), then an employee can no longer contribute to his/her 401a account.
In order to show how much an employee would contribute to their 401a account for Jan, Feb, Mar, etc., I need to reference the previous month totals. For example, for the February print iteration, the formula for 401a contributions needs to reference the sum total of personal contributions in January and February. Using the wonderful example of code provided by Chip Jarred (thank you!!), if we set the value of monthly to 15203.0 and the personal401kPercentage to 100% (for demonstration purposes only), this would be the result:
The sum total of $1,520, $13,683, $730, & $6,567 equals $22,500. But the sum of February only ($730 & $6,567 = $7,297) is less than the amount the employee would like to contribute (100% of monthly pay: $15,203). Consequently, in February the 401a deposit should be $7,906 ($730 + $6,567 + $7,906 = $15,203).
In my view, the first step in achieving this functionality is to store and set in the initializer the cumulative totals for personal contributions for each month. (Later we will probably need the cumulative totals for company AND personal contributions in order to know when we've reached $66,000 in order to stop contributing the 401a account. But we can probably address that later).
Here is my attempt at adding a yearToDate property to MonthlyContributions....
extension MonthlyContributions
{
var total: Decimal { roth + traditional }
init(combinedAmount: Decimal, rothPercentage: Decimal)
{
let roth = roundToNearestPenny(
percentage: rothPercentage,
of: combinedAmount
)
self.init(roth: roth, traditional: combinedAmount - roth)
}
}
extension MonthlyContributions
{
var yearToDate: Decimal { total }
init(combinedAmount: Decimal, limit: Decimal)
{
let totalContributions = calculateCombinedContribution(
monthlyContribution : total,
annualContributionLimit : limit,
contributionsSoFarThisYear: yearToDate
)
}
}
Unfortunately this was unsuccessful as using
print(" Total : $\(curContribution.yearToDate)")
only prints singular month totals, not a running cumulative total.