Skip to content

Instantly share code, notes, and snippets.

@623637646
Last active April 25, 2020 14:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save 623637646/29de625a7acb12fed4aa1ece81a51558 to your computer and use it in GitHub Desktop.
Save 623637646/29de625a7acb12fed4aa1ece81a51558 to your computer and use it in GitHub Desktop.
Calculate interest
//
// 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