Skip to content

Commit

Permalink
tolerance steps simplification
Browse files Browse the repository at this point in the history
  • Loading branch information
simontreanor committed Oct 11, 2024
1 parent 2b5e3cf commit b8dfe2b
Show file tree
Hide file tree
Showing 3 changed files with 10 additions and 9 deletions.
4 changes: 2 additions & 2 deletions src/Apr.fs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ module Apr =
let pp = calc a'k' unitPeriodRate
let difference = Decimal.Round(pp - aa, 8)
difference
Array.solve generator 100 roughApr AroundZero ValueNone
Array.solve generator 100 roughApr AroundZero ToleranceSteps.None

/// APR as in https://www.consumerfinance.gov/rules-policy/regulations/1026/j/
module UsActuarial =
Expand Down Expand Up @@ -226,7 +226,7 @@ module Apr =
let pp = calc ft unitPeriodRate
let difference = Decimal.Round(pp - aa, 10)
difference
Array.solve generator 100 roughUnitPeriodRate AroundZero ValueNone
Array.solve generator 100 roughUnitPeriodRate AroundZero ToleranceSteps.None
match unitPeriodRate with
| Solution.Found(upr, iteration, tolerance) ->
Solution.Found (annualPercentageRate upr unitPeriodsPerYear, iteration, tolerance)
Expand Down
13 changes: 7 additions & 6 deletions src/Array.fs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ module ArrayExtension =
Max: int
}
with
static member forPaymentValue paymentCount =
static member None =
{ ToleranceSteps.Min = 0; ToleranceSteps.Step = 0; ToleranceSteps.Max = 0 }
static member ForPaymentValue paymentCount =
{ ToleranceSteps.Min = 0; ToleranceSteps.Step = paymentCount; ToleranceSteps.Max = paymentCount * 4 }

/// what range of values the solver should aim for
Expand All @@ -41,8 +43,7 @@ module ArrayExtension =
/// iteratively solves for a given input using a generator function until the output is 0L<Cent> or within a set tolerance,
/// optionally relaxing the tolerance until a solution is found
[<TailCall>]
let solve (generator: decimal -> decimal) iterationLimit approximation toleranceOption (toleranceSteps: ToleranceSteps voption) =
let toleranceSteps' = toleranceSteps |> ValueOption.defaultValue { Min = 0; Step = 0; Max = 0 }
let solve (generator: decimal -> decimal) iterationLimit approximation toleranceOption (toleranceSteps: ToleranceSteps) =
let rec loop i lowerBound upperBound tolerance =
let midRange =
let x = (upperBound - lowerBound) / 2m
Expand All @@ -51,10 +52,10 @@ module ArrayExtension =
else x
let newBound = lowerBound + midRange
if i = iterationLimit then
if tolerance = toleranceSteps'.Max then
if tolerance = toleranceSteps.Max then
Solution.IterationLimitReached (newBound, i, tolerance)
else
let newTolerance = min toleranceSteps'.Max (tolerance + toleranceSteps'.Step)
let newTolerance = min toleranceSteps.Max (tolerance + toleranceSteps.Step)
loop 0 0m (approximation * 100m) newTolerance
else
let difference = generator newBound
Expand All @@ -69,4 +70,4 @@ module ArrayExtension =
loop (i + 1) newBound upperBound tolerance
else //difference < lowerTolerance
loop (i + 1) lowerBound newBound tolerance
loop 0 0m (approximation * 100m) toleranceSteps'.Min // to do: improve approximation
loop 0 0m (approximation * 100m) toleranceSteps.Min // to do: improve approximation
2 changes: 1 addition & 1 deletion src/PaymentSchedule.fs
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,7 @@ module PaymentSchedule =

let mutable schedule = [||]

let toleranceSteps = ValueSome <| ToleranceSteps.forPaymentValue paymentCount
let toleranceSteps = ToleranceSteps.ForPaymentValue paymentCount

let calculateInterest interestMethod payment previousItem day =
match interestMethod with
Expand Down

0 comments on commit b8dfe2b

Please sign in to comment.