lmi-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[lmi-commits] [lmi] master 026214c 4/8: Solve for currency rather than d


From: Greg Chicares
Subject: [lmi-commits] [lmi] master 026214c 4/8: Solve for currency rather than double
Date: Tue, 26 Jan 2021 08:12:31 -0500 (EST)

branch: master
commit 026214ceb6fff5affde0d4c7a341a0e9c2dfc6b9
Author: Gregory W. Chicares <gchicares@sbcglobal.net>
Commit: Gregory W. Chicares <gchicares@sbcglobal.net>

    Solve for currency rather than double
---
 ihs_avsolve.cpp | 61 ++++++++++++++++++++++++++++++++++-----------------------
 solve.cpp       | 41 +++++++++++++++++++++-----------------
 2 files changed, 59 insertions(+), 43 deletions(-)

diff --git a/ihs_avsolve.cpp b/ihs_avsolve.cpp
index 3fb7c03..79cdb89 100644
--- a/ihs_avsolve.cpp
+++ b/ihs_avsolve.cpp
@@ -65,10 +65,11 @@ class SolveHelper
     // so
     //   double function(double)
     // is the appropriate signature here. Someday it might make sense
-    // to modify decimal_root to work with currency types directly.
+    // to modify decimal_root to work with currency types directly,
+    // or at least to make this function take a 'currency' argument.
     double operator()(double a_CandidateValue)
         {
-        return av.SolveTest(a_CandidateValue);
+        return dblize(av.SolveTest(av.round_minutiae().c(a_CandidateValue)));
         }
 };
 
@@ -184,30 +185,33 @@ currency AccountValue::SolveTest(currency 
a_CandidateValue)
         ,0
         );
     LMI_ASSERT(0 <= no_lapse_dur);
-    double most_negative_csv = 0.0;
+    currency most_negative_csv = C0;
     if(no_lapse_dur < SolveTargetDuration_)
         {
-        most_negative_csv = *std::min_element
-            (VariantValues().CSVNet.begin() + no_lapse_dur
-            ,VariantValues().CSVNet.begin() + SolveTargetDuration_
+        // CURRENCY !! Cents in ledger will make rounding unnecessary.
+        most_negative_csv = round_minutiae().c
+            (*std::min_element
+                (VariantValues().CSVNet.begin() + no_lapse_dur
+                ,VariantValues().CSVNet.begin() + SolveTargetDuration_
+                )
             );
         }
 
     // AccountValue::Solve() asserts that SolveTargetDuration_ lies
     // within appropriate bounds.
-    double greatest_loan_ullage = *std::max_element
+    currency greatest_loan_ullage = *std::max_element
         (loan_ullage_.begin()
         ,loan_ullage_.begin() + SolveTargetDuration_
         );
-    double greatest_withdrawal_ullage = *std::max_element
+    currency greatest_withdrawal_ullage = *std::max_element
         (withdrawal_ullage_.begin()
         ,withdrawal_ullage_.begin() + SolveTargetDuration_
         );
-    double greatest_ullage = std::max
+    currency greatest_ullage = std::max
         (greatest_loan_ullage
         ,greatest_withdrawal_ullage
         );
-    double worst_negative = std::min
+    currency worst_negative = std::min
         (most_negative_csv
         ,-greatest_ullage
         );
@@ -215,15 +219,18 @@ currency AccountValue::SolveTest(currency 
a_CandidateValue)
     // SolveTargetDuration_ is in origin one. That's natural for loop
     // counters and iterators--it's one past the end--but indexing
     // must decrement it.
-    double value = VariantValues().CSVNet[SolveTargetDuration_ - 1];
+    // CURRENCY !! Cents in ledger will make rounding unnecessary.
+    currency value = 
round_minutiae().c(VariantValues().CSVNet[SolveTargetDuration_ - 1]);
     if(mce_solve_for_target_naar == SolveTarget_)
         {
-        value =
+        // CURRENCY !! Cents in ledger will make rounding unnecessary.
+        value = round_minutiae().c
+            (
               VariantValues().EOYDeathBft[SolveTargetDuration_ - 1]
             - VariantValues().AcctVal    [SolveTargetDuration_ - 1]
-            ;
+            );
         }
-    if(worst_negative < 0.0)
+    if(worst_negative < C0)
         {
         value = std::min(value, worst_negative);
         }
@@ -242,7 +249,8 @@ currency AccountValue::SolveTest(currency a_CandidateValue)
 
     if(mce_solve_for_non_mec == SolveTarget_)
         {
-        return InvariantValues().IsMec ? -1.0 : 1.0;
+        static const currency C100 = from_cents(100); // one dollar
+        return InvariantValues().IsMec ? -C100 : C100;
         }
 
     return value - SolveTargetCsv_;
@@ -287,21 +295,21 @@ void AccountValue::SolveSetWD(currency a_CandidateValue)
 currency AccountValue::SolveGuarPremium()
 {
     // Store original er premiums for later restoration.
-    std::vector<double> stored = Outlay_->er_modal_premiums();
+    std::vector<currency> stored = Outlay_->er_modal_premiums();
     // Zero out er premiums and solve for ee premiums only.
-    Outlay_->set_er_modal_premiums(0.0, 0, BasicValues::GetLength());
+    Outlay_->set_er_modal_premiums(C0, 0, BasicValues::GetLength());
 
     bool temp_solving     = Solving;
     Solving               = true;
     SolvingForGuarPremium = true;
 
     // Run the solve using guaranteed assumptions.
-    double guar_premium = Solve
+    currency guar_premium = Solve
         (mce_solve_ee_prem
         ,0
         ,BasicValues::GetLength()
         ,mce_solve_for_endt
-        ,0.0
+        ,C0
         ,BasicValues::GetLength()
         ,mce_gen_guar
         ,mce_sep_full
@@ -369,10 +377,12 @@ currency AccountValue::Solve
             // Generally, base and term are independent, and it is
             // the base specamt that's being solved for here, so set
             // the minimum as though there were no term.
-            lower_bound = minimum_specified_amount
-                (  0 == SolveBeginYear_
-                && yare_input_.EffectiveDate == yare_input_.InforceAsOfDate
-                ,false
+            lower_bound = dblize
+                (minimum_specified_amount
+                    (  0 == SolveBeginYear_
+                    && yare_input_.EffectiveDate == yare_input_.InforceAsOfDate
+                    ,false
+                    )
                 );
             }
             break;
@@ -453,6 +463,7 @@ currency AccountValue::Solve
     // are stored now, and values are regenerated downstream.
 
     Solving = false;
-    (this->*solve_set_fn)(solution.first);
-    return solution.first;
+    currency const solution_cents = round_minutiae().c(solution.first);
+    (this->*solve_set_fn)(solution_cents);
+    return solution_cents;
 }
diff --git a/solve.cpp b/solve.cpp
index 89023b6..3216232 100644
--- a/solve.cpp
+++ b/solve.cpp
@@ -30,6 +30,7 @@
 #include "ledger_variant.hpp"
 #include "mc_enum_types_aux.hpp"        // set_run_basis_from_cloven_bases()
 #include "outlay.hpp"
+#include "round_to.hpp"
 #include "zero.hpp"
 
 #include <algorithm>                    // max(), min()
@@ -57,6 +58,8 @@ namespace
     int                 ThatSolveEndYear;
     mcenum_gen_basis    ThatSolveBasis;
     bool                only_set_values;
+
+    round_to<double> const round_to_cents(2, r_to_nearest);
 } // Unnamed namespace.
 
 //============================================================================
@@ -80,26 +83,28 @@ currency SolveTest()
     //   CSV at target duration
     //   lowest negative CSV through target duration
     //   amount of loan in excess of maximum loan through target duration
-    double Negative = 0.0;
+    currency Negative = C0;
 
     // IHS !! Start counting only at end of no-lapse period--lmi does that 
already.
     for(int j = 0; j < ThatSolveTgtYear; ++j)
         {
         Negative = std::min
             (Negative
-            ,ConstThat->VariantValues().CSVNet[j]
+            // CURRENCY !! Cents in ledger will make rounding unnecessary.
+            ,round_to_cents.c(ConstThat->VariantValues().CSVNet[j])
 // Ideally, it'd be this:
 //          ,std::min(ConstThat->VariantValues().CSVNet[j], 
ConstThat->loan_ullage_[j])
 // but the antediluvian branch doesn't calculate ullage at all.
             );
         }
 
-    double z = ConstThat->VariantValues().CSVNet[ThatSolveTgtYear - 1];
-    if(Negative < 0.0)
+    // CURRENCY !! Cents in ledger will make rounding unnecessary.
+    currency z = 
round_to_cents.c(ConstThat->VariantValues().CSVNet[ThatSolveTgtYear - 1]);
+    if(Negative < C0)
         z = std::min(z, Negative);
     // IHS !! If SolveTgtYr within no-lapse period...see lmi.
 
-    double y = 0.0;
+    currency y = C0;
     switch(ThatSolveTarget)
         {
         case mce_solve_for_endt:
@@ -134,7 +139,7 @@ currency SolveTest()
             break;
         case mce_solve_for_target_csv:
             {
-            y = ThatSolveTargetValue;
+            y = round_to_cents.c(ThatSolveTargetValue);
             }
             break;
         case mce_solve_for_target_naar: // Fall through.
@@ -154,29 +159,29 @@ currency SolveTest()
 inline static double SolveSpecAmt(double CandidateValue)
 {
 // IHS !! Change surrchg when SA changes?
-    That->SolveSetSpecAmt(CandidateValue, ThatSolveBegYear, ThatSolveEndYear);
-    return only_set_values ? 0.0 : SolveTest();
+    That->SolveSetSpecAmt(round_to_cents.c(CandidateValue), ThatSolveBegYear, 
ThatSolveEndYear);
+    return only_set_values ? 0.0 : dblize(SolveTest());
 }
 
 //============================================================================
 inline static double SolvePrem(double CandidateValue)
 {
-    That->SolveSetPmts(CandidateValue, ThatSolveBegYear, ThatSolveEndYear);
-    return only_set_values ? 0.0 : SolveTest();
+    That->SolveSetPmts(round_to_cents.c(CandidateValue), ThatSolveBegYear, 
ThatSolveEndYear);
+    return only_set_values ? 0.0 : dblize(SolveTest());
 }
 
 //============================================================================
 inline static double SolveLoan(double CandidateValue)
 {
-    That->SolveSetLoans(CandidateValue, ThatSolveBegYear, ThatSolveEndYear);
-    return only_set_values ? 0.0 : SolveTest();
+    That->SolveSetLoans(round_to_cents.c(CandidateValue), ThatSolveBegYear, 
ThatSolveEndYear);
+    return only_set_values ? 0.0 : dblize(SolveTest());
 }
 
 //============================================================================
 inline static double SolveWD(double CandidateValue)
 {
-    That->SolveSetWDs(CandidateValue, ThatSolveBegYear, ThatSolveEndYear);
-    return only_set_values ? 0.0 : SolveTest();
+    That->SolveSetWDs(round_to_cents.c(CandidateValue), ThatSolveBegYear, 
ThatSolveEndYear);
+    return only_set_values ? 0.0 : dblize(SolveTest());
 }
 
 //============================================================================
@@ -279,7 +284,7 @@ currency AccountValue::Solve()
             LowerBound = 0.0;
             // If solved premium exceeds specified amount, there's a problem.
             // IHS !! Better to use the maximum SA, not the first SA?
-            UpperBound = DeathBfts_->specamt()[0];
+            UpperBound = dblize(DeathBfts_->specamt()[0]);
             Decimals   = 2;
             SolveFn    = SolvePrem;
             }
@@ -347,8 +352,8 @@ currency AccountValue::Solve()
     // generate or analyze account values. This global variable is a
     // kludge, but so is 'That'; a function object is wanted instead.
     only_set_values = !Solving;
-    double actual_solution = Solution.first;
 
-    SolveFn(actual_solution);
-    return actual_solution;
+    currency const solution_cents = round_to_cents.c(Solution.first);
+    SolveFn(dblize(solution_cents));
+    return solution_cents;
 }



reply via email to

[Prev in Thread] Current Thread [Next in Thread]