Last active
April 25, 2020 14:06
-
-
Save 623637646/29de625a7acb12fed4aa1ece81a51558 to your computer and use it in GitHub Desktop.
Calculate interest
This file contains 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
// | |
// InterestTests.swift | |
// iOSHookTests | |
// | |
// Created by Yanni Wang on 25/4/20. | |
// Copyright © 2020 Yanni. All rights reserved. | |
// | |
import XCTest | |
class InterestTests: XCTestCase { | |
func testGetInterestPeriodRate() { | |
for _ in 0 ... 100 { | |
let principalAmount: Double = Double.random(in: 1 ... 1000 * 10000) | |
let interestAmount: Double = Double.random(in: 0 ... principalAmount) | |
let period: Int = Int.random(in: 1 ... 200) | |
let interestPeriodRate = getInterestPeriodRate(principalAmount: principalAmount, interestAmount: interestAmount, period: period) | |
let periodPaidByFormula = getPeriodPaidByFormula(principalAmount: principalAmount, interestPeriodRate: interestPeriodRate, period: period) | |
let interestAmountByFormula = periodPaidByFormula * Double(period) - principalAmount | |
XCTAssertTrue(fabs(interestAmountByFormula - interestAmount) < 0.01, "diff is \(fabs(interestAmountByFormula - interestAmount))") | |
} | |
} | |
func testGetPeriodPaid() { | |
for _ in 0 ... 100 { | |
let interestPeriodRate: Double = Double.random(in: 0 ... 1 / 12) | |
let principalAmount: Double = Double.random(in: 1 ... 1000 * 10000) | |
let period: Int = Int.random(in: 1 ... 200) | |
let periodPaid = getPeriodPaid(principalAmount: principalAmount, interestPeriodRate: interestPeriodRate, period: period) | |
let periodPaidByFormula = getPeriodPaidByFormula(principalAmount: principalAmount, interestPeriodRate: interestPeriodRate, period: period) | |
XCTAssertTrue(fabs(periodPaid - periodPaidByFormula) < 0.01, "diff is \(fabs(periodPaid - periodPaidByFormula))") | |
} | |
} | |
func testBestPeriod() { | |
let principalAmount: Double = 500000 | |
let interestPeriodRate: Double = 6.3/100/12 | |
let periodMax: Int = 95 | |
var programs = [(period: Int, interestYearRate: Double)]() | |
for period in 1 ... periodMax { | |
let interestAmount = principalAmount * interestPeriodRate * Double(period) | |
let interestYearRate = getInterestPeriodRate(principalAmount: principalAmount, interestAmount: interestAmount, period: period) * 12 | |
programs.append((period, interestYearRate)) | |
} | |
for (period, interestYearRate) in programs { | |
print("期数: \(period), 年利率: \(String(format: "%.2f", interestYearRate * 100))%") | |
} | |
} | |
// MARK: utilities | |
func getPeriodPaid(principalAmount: Double, interestPeriodRate: Double, period: Int) -> Double { | |
let tolerance: Double = 0.01 | |
var periodPaidMin = principalAmount / Double(period) | |
var periodPaidMax = (principalAmount + principalAmount * interestPeriodRate * Double(period)) / Double(period) | |
var periodPaid = periodPaidMin | |
while true { | |
var paidPrincipal: Double = 0 | |
var paidInterest: Double = 0 | |
for _ in 1 ... period { | |
let currentInterest = (principalAmount - paidPrincipal) * interestPeriodRate | |
paidInterest += currentInterest | |
paidPrincipal += periodPaid - currentInterest | |
} | |
if fabs(paidPrincipal - principalAmount) <= tolerance { | |
break | |
} else if (paidPrincipal > principalAmount){ | |
periodPaidMax = periodPaid | |
periodPaid -= (periodPaid - periodPaidMin) / 2 | |
} else { | |
periodPaidMin = periodPaid | |
periodPaid += (periodPaidMax - periodPaid) / 2 | |
} | |
} | |
return periodPaid | |
} | |
func getInterestPeriodRate(principalAmount: Double, interestAmount: Double, period: Int) -> Double { | |
let tolerance: Double = 0.00000000001 | |
let periodPaid = (principalAmount + interestAmount) / Double(period) | |
var interestPeriodRateMin = 0 as Double | |
var interestPeriodRateMax = periodPaid / principalAmount | |
var interestPeriodRate = interestPeriodRateMin | |
while true { | |
var paidPrincipal: Double = 0 | |
var paidInterest: Double = 0 | |
for _ in 1 ... period { | |
let currentInterest = (principalAmount - paidPrincipal) * interestPeriodRate | |
paidInterest += currentInterest | |
paidPrincipal += periodPaid - currentInterest | |
} | |
if fabs(interestPeriodRateMax - interestPeriodRateMin) <= tolerance { | |
break | |
} else if (paidPrincipal < principalAmount){ | |
interestPeriodRateMax = interestPeriodRate | |
interestPeriodRate -= (interestPeriodRate - interestPeriodRateMin) / 2 | |
} else { | |
interestPeriodRateMin = interestPeriodRate | |
interestPeriodRate += (interestPeriodRateMax - interestPeriodRate) / 2 | |
} | |
} | |
return interestPeriodRate | |
} | |
func getPeriodPaidByFormula(principalAmount: Double, interestPeriodRate: Double, period: Int) -> Double { | |
return principalAmount * interestPeriodRate * pow((1 + interestPeriodRate), Double(period)) / (pow((1 + interestPeriodRate), Double(period)) - 1) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment