[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[lmi-commits] [lmi] valyuta/002 a32e29b 53/65: Avoid implicit conversion
From: |
Greg Chicares |
Subject: |
[lmi-commits] [lmi] valyuta/002 a32e29b 53/65: Avoid implicit conversions, whose (hidden) cost is very high |
Date: |
Wed, 16 Sep 2020 16:55:21 -0400 (EDT) |
branch: valyuta/002
commit a32e29bb3cb728eb63687ed81e54f33e5da4a428
Author: Gregory W. Chicares <gchicares@sbcglobal.net>
Commit: Gregory W. Chicares <gchicares@sbcglobal.net>
Avoid implicit conversions, whose (hidden) cost is very high
---
README.branch.patch | 77 +++++++++++
accountvalue.cpp | 65 +++++-----
basicvalues.cpp | 4 +-
currency.hpp | 8 +-
gpt_specamt.cpp | 6 +-
ihs_acctval.cpp | 165 ++++++++++++------------
ihs_avdebug.cpp | 8 +-
ihs_avmly.cpp | 318 +++++++++++++++++++++++-----------------------
ihs_avsolve.cpp | 19 +--
ihs_avstrtgy.cpp | 10 +-
ihs_basicval.cpp | 38 +++---
ledger_invariant_init.cpp | 4 +-
ledgervalues.cpp | 4 +-
solve.cpp | 18 +--
14 files changed, 416 insertions(+), 328 deletions(-)
diff --git a/README.branch.patch b/README.branch.patch
index 744b789..8f426c7 100644
--- a/README.branch.patch
+++ b/README.branch.patch
@@ -1,3 +1,80 @@
+Make conversions explicit, e.g.:
+ currency amount;
+- amount = 3.14; // implicit
++ amount = currency(3.14); // explicit
+ double floating;
+- floating = amount; // was implicit
++ floating = amount.d();
+That may seem like mere ugly verbosity, but...
+- amount = 0.0; // (integer)(round(100.0 * 0.0))
++ amount = currency(); // integer = 0
++ currency amount {}; // even better, where possible
+- if(0.0 == amount) // 0.0 == (double)(amount / 100.0)
++ if(currency() == amount) // integer == integer
+A user-defined literals like "0_c" could replace
+
+Removed the very costly implicit conversions:
+ currency& operator=(double d)
+ operator double() const
+but allowed
+ currency& operator=(int i) // assigns 100.0 * argument
+
+Because using integer math means not having to worry about catastrophic
+cancellation, made improvements like this:
+
+- LMI_ASSERT(materially_equal(GrossPmts[j], EeGrossPmts[j] + ErGrossPmts[j]));
++ LMI_ASSERT(GrossPmts[j] == EeGrossPmts[j] + ErGrossPmts[j]);
+
+ double max_loan =
+ AVUnloaned.d() * 0.9
+ + (AVRegLn + AVPrfLn).d()
+ - RegLnBal.d() * i_reg
+ - PrfLnBal.d() * i_prf
+ - mlydedtonextmodalpmtdate.d()
+ ;
+
+random notes--further cleanup and other future tasks:
+
++ if(currency() == RegLnBal && 0.0 == PrfLnBal)
+ ^^^ should be "currency()"
+
+max<double>...should rarely if ever need to specify template parameter
+
+should be currency():
++ AVUnloaned = 0; // Antediluvian.
+
+unary operator-()
+
+loads class should use currency type for policy fees
+
+probably DCV should be currency instead of double
+
+Solves are still a puzzle: is it inherently slower to find an
+integral root than a floating-point root of a polynomial? That
+question is crucial because making solves dramatically slower
+could mean that a currency class is unaffordable.
+
+After the changes in this commit:
+
+ naic, no solve : 1.085e-01 s mean; 103995 us least of 10 runs
+ naic, specamt solve : 1.798e-01 s mean; 179138 us least of 6 runs
+ naic, ee prem solve : 1.672e-01 s mean; 166277 us least of 6 runs
+ finra, no solve : 2.711e-02 s mean; 26542 us least of 37 runs
+ finra, specamt solve: 9.375e-02 s mean; 93087 us least of 11 runs
+ finra, ee prem solve: 8.994e-02 s mean; 89230 us least of 12 runs
+
+which is about ten percent faster for "finra, no solve", the
+only scenario that involves no explicit or implicit solve,
+so these improvements are valuable even if making all the
+conversions explicit impairs readability somewhat. Still,
+solves need to be looked at. Compared to production, even with
+these changes the currency branch is thirty percent slower for the
+"finra, no solve" case (yet further improvements might bring that
+into an acceptable range), but only half as fast for the "naic"
+scenarios (which involve solves).
+
+//
+
As of
commit 7bac50c7154a419ff93a1398313dc7fe6d9fbed5 (HEAD -> valyuta/002)
Date: 2020-09-13T23:50:07+00:00
diff --git a/accountvalue.cpp b/accountvalue.cpp
index 21c475e..e8bbe46 100644
--- a/accountvalue.cpp
+++ b/accountvalue.cpp
@@ -228,19 +228,19 @@ currency AccountValue::RunOneCell(mcenum_run_basis
TheBasis)
InforceYear = yare_input_.InforceYear;
InforceMonth = yare_input_.InforceMonth;
- InforceAVGenAcct = yare_input_.InforceGeneralAccountValue;
+ InforceAVGenAcct = currency(yare_input_.InforceGeneralAccountValue);
ItLapsed = false;
LapseMonth = 0;
LapseYear = 0;
- TaxBasis = 0.0;
+ TaxBasis = currency();
- MaxLoan = 0.0;
- RegLnBal = 0.0;
- PrfLnBal = 0.0;
- AVRegLn = 0.0;
- AVPrfLn = 0.0;
+ MaxLoan = currency();
+ RegLnBal = currency();
+ PrfLnBal = currency();
+ AVRegLn = currency();
+ AVPrfLn = currency();
// 'InforceAVGenAcct' is unloaned only; this branch wasn't
// designed to allow inforce loans.
@@ -290,7 +290,7 @@ void AccountValue::DoYear
pmt = stored_pmts[Year];
YearsPremLoadTgt = Loads_->target_premium_load(GenBasis_)[Year];
- YearsMonthlyPolicyFee = Loads_->monthly_policy_fee(GenBasis_)[Year];
+ YearsMonthlyPolicyFee =
currency(Loads_->monthly_policy_fee(GenBasis_)[Year]);
ActualSpecAmt = base_specamt(Year);
// These variables are set for each pass independently.
@@ -345,16 +345,16 @@ void AccountValue::DoYear
}
}
- VariantValues().AcctVal[Year] = AVUnloaned + AVRegLn + AVPrfLn;
+ VariantValues().AcctVal[Year] = (AVUnloaned + AVRegLn + AVPrfLn).d();
VariantValues().CSVNet[Year] = VariantValues().AcctVal[Year] -
VariantValues().SurrChg[Year];
// Update death benefit: "deathbft" currently holds benefit as of the
// beginning of month 12, but we want it as of the end of that month,
// in case the corridor or option 2 drove it up during the last month.
TxSetDeathBft();
- VariantValues().EOYDeathBft[Year] = deathbft;
+ VariantValues().EOYDeathBft[Year] = deathbft.d();
// IHS !! Change one of these names, which differ only in the terminal 's'.
- InvariantValues().GrossPmt[Year] += std::accumulate(GrossPmts.begin(),
GrossPmts.end(), 0.0);
+ InvariantValues().GrossPmt[Year] += std::accumulate(GrossPmts.begin(),
GrossPmts.end(), currency()).d();
InvariantValues().Outlay[Year] =
InvariantValues().GrossPmt [Year]
- InvariantValues().NetWD [Year]
@@ -497,7 +497,7 @@ void AccountValue::PerformSpecAmtStrategy()
for(int j = 0; j < BasicValues::GetLength(); ++j)
{
- InvariantValues().SpecAmt[j] = SA;
+ InvariantValues().SpecAmt[j] = SA.d();
}
}
@@ -557,7 +557,7 @@ void AccountValue::TxOptionChange()
// Carry the new spec amt forward into all future years.
for(int j = Year; j < BasicValues::GetLength(); ++j)
{
- InvariantValues().SpecAmt[j] = ActualSpecAmt;
+ InvariantValues().SpecAmt[j] = ActualSpecAmt.d();
}
}
@@ -589,7 +589,7 @@ void AccountValue::TxSpecAmtChange()
// Carry the new spec amt forward into all future years.
for(int j = Year; j < BasicValues::GetLength(); ++j)
{
- InvariantValues().SpecAmt[j] = ActualSpecAmt;
+ InvariantValues().SpecAmt[j] = ActualSpecAmt.d();
}
}
@@ -734,7 +734,7 @@ void AccountValue::TxLoanRepay()
AVUnloaned -= RequestedLoan;
AVRegLn += RequestedLoan; // IHS !! Preferred loans--see lmi.
- InvariantValues().NewCashLoan[Year] = RequestedLoan;
+ InvariantValues().NewCashLoan[Year] = RequestedLoan.d();
}
/// Set account value before monthly deductions.
@@ -790,7 +790,8 @@ void AccountValue::TxSetCoiCharge()
TxSetDeathBft();
// Negative AV doesn't increase NAAR.
- NAAR = round_naar()(deathbft * mlyguarv - (AVUnloaned + AVRegLn +
AVPrfLn));
+ NAAR = (deathbft * mlyguarv - (AVUnloaned + AVRegLn + AVPrfLn)).d();
+ NAAR = round_naar()(NAAR);
CoiCharge = round_coi_charge().c(NAAR * YearsCoiRate0);
}
@@ -799,19 +800,20 @@ void AccountValue::TxSetCoiCharge()
void AccountValue::TxSetRiderDed()
{
- WpCharge = 0.0;
+ WpCharge = currency();
if(haswp)
{
- WpCharge =
+ WpCharge = currency
+ (
YearsWpRate
* (CoiCharge + YearsMonthlyPolicyFee + AdbCharge)
- ;
+ );
}
- AdbCharge = 0.0;
+ AdbCharge = currency();
if(hasadb)
{
- AdbCharge = currency(YearsAdbRate * std::min<double>(500000.0,
ActualSpecAmt));
+ AdbCharge = currency(YearsAdbRate * std::min<double>(500000.0,
ActualSpecAmt.d()));
}
}
@@ -879,7 +881,7 @@ void AccountValue::TxTakeWD()
}
// Nothing to do if no withdrawal requested.
- if(0.0 == wd)
+ if(currency() == wd)
{
return;
}
@@ -889,7 +891,7 @@ void AccountValue::TxTakeWD()
// Impose minimum amount (if nonzero) on withdrawals.
if(wd < MinWD)
{
- wd = 0.0;
+ wd = currency();
}
// Impose maximum amount.
@@ -934,7 +936,7 @@ void AccountValue::TxTakeWD()
// Carry the new spec amt forward into all future years.
for(int j = Year; j < BasicValues::GetLength(); ++j)
{
- InvariantValues().SpecAmt[j] = ActualSpecAmt;
+ InvariantValues().SpecAmt[j] = ActualSpecAmt.d();
}
}
break;
@@ -953,7 +955,7 @@ void AccountValue::TxTakeWD()
wd -= std::min(WDFee, currency(wd * WDFeeRate));
// IHS !! This treats input WD as gross; it probably should be net. But
compare lmi.
- InvariantValues().NetWD[Year] = wd;
+ InvariantValues().NetWD[Year] = wd.d();
// IHS !! TaxBasis -= wd; // Withdrawals are subtracted from basis in lmi.
}
@@ -977,12 +979,13 @@ void AccountValue::TxTakeLoan()
// If maximum exceeded...limit it.
// IHS !! For solves, the lmi branch uses an 'ullage' concept.
double max_loan =
- AVUnloaned * 0.9 // IHS !! Icky manifest constant--lmi uses a
database entity.
+ AVUnloaned.d() * 0.9 // IHS !! Icky manifest constant--lmi uses a
database entity.
// - surrchg
- + (AVRegLn + AVPrfLn)
- - RegLnBal * (std::pow((1.0 + YearsRegLnIntDueRate), 12 - Month) - 1.0)
- - PrfLnBal * (std::pow((1.0 + YearsPrfLnIntDueRate), 12 - Month) - 1.0)
- - mlydedtonextmodalpmtdate;
+ + (AVRegLn + AVPrfLn).d()
+ - RegLnBal.d() * (std::pow((1.0 + YearsRegLnIntDueRate), 12 - Month) -
1.0)
+ - PrfLnBal.d() * (std::pow((1.0 + YearsPrfLnIntDueRate), 12 - Month) -
1.0)
+ - mlydedtonextmodalpmtdate.d()
+ ;
// Interest adjustment: d upper n where n is # months remaining in year.
// Witholding this keeps policy from becoming overloaned before year end.
double IntAdj = std::pow((1.0 + YearsRegLnIntDueRate), 12 - Month);
@@ -1002,7 +1005,7 @@ void AccountValue::TxTakeLoan()
AVUnloaned -= RequestedLoan;
AVRegLn += RequestedLoan; // IHS !! Also preferred loans: implemented
in lmi.
- InvariantValues().NewCashLoan[Year] = RequestedLoan;
+ InvariantValues().NewCashLoan[Year] = RequestedLoan.d();
}
/// Test for lapse.
diff --git a/basicvalues.cpp b/basicvalues.cpp
index 4c4a2ab..7c593c3 100644
--- a/basicvalues.cpp
+++ b/basicvalues.cpp
@@ -200,7 +200,7 @@ currency BasicValues::GetModalTgtPrem
// IHS !! Implemented better in lmi.
double Annuity = (1.0 - std::pow(u, 12 / a_mode)) / (1.0 - u);
- double z = a_specamt;
+ double z = a_specamt.d();
z /=
( 1.0
+ InterestRates_->GenAcctNetRate
@@ -274,7 +274,7 @@ currency BasicValues::GetModalTgtSpecAmt
);
double Annuity = (1.0 - std::pow(u, 12 / a_mode)) / (1.0 - u);
- double z = a_pmt;
+ double z = a_pmt.d();
z /= Annuity;
z *= 1.0 - Loads_->target_premium_load(mce_gen_curr)[0];
// z /= WpRate;
diff --git a/currency.hpp b/currency.hpp
index 0a54a91..133aa16 100644
--- a/currency.hpp
+++ b/currency.hpp
@@ -64,16 +64,16 @@ class currency
~currency() = default;
explicit currency(double d) : m_ {from_double(d)} {}
- explicit currency(int i) : m_ {bourn_cast<data_type>(i)} {}
+ explicit currency(int i) : m_ {cents_per_dollar *
bourn_cast<data_type>(i)} {}
explicit currency(data_type i) : m_ {bourn_cast<data_type>(i)} {}
currency& operator=(currency const&) = default;
// IMPORTANT eventually suppress this? or both of these?
// defining both causes real problems
- currency& operator=(double d) {m_ = from_double(d); return
*this;}
-// currency& operator=(int i) {m_ = bourn_cast<data_type>(i); return
*this;}
+// currency& operator=(double d) {m_ = from_double(d); return
*this;}
+ currency& operator=(int i) {m_ = cents_per_dollar *
bourn_cast<data_type>(i); return *this;}
- operator double() const {return to_double();}
+// operator double() const {return to_double();}
double d() const {return to_double();}
#if 0
diff --git a/gpt_specamt.cpp b/gpt_specamt.cpp
index e7b192d..e2b67fe 100644
--- a/gpt_specamt.cpp
+++ b/gpt_specamt.cpp
@@ -107,14 +107,14 @@ class FindSpecAmt
,a_Trial
,NetPmtFactorTgt
,NetPmtFactorExc
- ,Values_.GetAnnualTgtPrem(Duration, SpecAmt)
+ ,Values_.GetAnnualTgtPrem(Duration, SpecAmt).d()
)
- Premium
;
}
double Get()
{
- return SpecAmt;
+ return SpecAmt.d();
}
};
@@ -150,7 +150,7 @@ currency gpt_specamt::CalculateSpecAmt
,z
,a_EIOBasis
,a_Duration
- ,a_Premium
+ ,a_Premium.d()
,a_NetPmtFactorTgt
,a_NetPmtFactorExc
);
diff --git a/ihs_acctval.cpp b/ihs_acctval.cpp
index 0f51640..7dd48e0 100644
--- a/ihs_acctval.cpp
+++ b/ihs_acctval.cpp
@@ -111,16 +111,16 @@ AccountValue::AccountValue(Input const& input)
// all be kept together.
LapseMonth = 0; // Antediluvian.
LapseYear = 0; // Antediluvian.
- AVUnloaned = 0.0; // Antediluvian.
- pmt = 0.0; // Antediluvian.
+ AVUnloaned = 0; // Antediluvian.
+ pmt = 0; // Antediluvian.
pmt_mode = mce_annual; // Antediluvian.
ModeIndex = 0; // Antediluvian.
- wd = 0.0; // Antediluvian.
+ wd = 0; // Antediluvian.
mlyguarv = 0.0; // Antediluvian.
- deathbft = 0.0; // Antediluvian.
+ deathbft = 0; // Antediluvian.
haswp = false; // Antediluvian.
hasadb = false; // Antediluvian.
- mlydedtonextmodalpmtdate = 0.0; // Antediluvian.
+ mlydedtonextmodalpmtdate = 0; // Antediluvian.
set_list_bill_year_and_month();
@@ -158,7 +158,7 @@ currency AccountValue::specamt_for_7702(int year) const
{
return
base_specamt(year)
- + (TermIsDbFor7702 ? term_specamt(year) : 0.0)
+ + (TermIsDbFor7702 ? term_specamt(year) : currency())
;
}
@@ -168,7 +168,7 @@ currency AccountValue::specamt_for_7702A(int year) const
{
return
base_specamt(year)
- + (TermIsDbFor7702A ? term_specamt(year) : 0.0)
+ + (TermIsDbFor7702A ? term_specamt(year) : currency())
;
}
@@ -217,13 +217,13 @@ Then run other bases.
// this rather expensive function.
void AccountValue::SetGuarPrem()
{
- GuarPremium = 0.0;
+ GuarPremium = currency();
if(BasicValues::IsSubjectToIllustrationReg())
{
GuarPremium = SolveGuarPremium();
}
LMI_ASSERT(GuarPremium < 1.0e100);
- ledger_->SetGuarPremium(GuarPremium);
+ ledger_->SetGuarPremium(GuarPremium.d());
}
//============================================================================
@@ -405,8 +405,8 @@ void AccountValue::InitializeLife(mcenum_run_basis a_Basis)
(0
,mce_annual
,base_specamt(0)
- );
- double sa = specamt_for_7702(0);
+ ).d();
+ double sa = specamt_for_7702(0).d();
// It is at best superfluous to do this for every basis.
// TAXATION !! Don't do that then.
@@ -450,7 +450,7 @@ void AccountValue::InitializeLife(mcenum_run_basis a_Basis)
if(yare_input_.EffectiveDate == yare_input_.InforceAsOfDate)
{
// No need to initialize 'pmts_7702a' in this case.
- bfts_7702a.push_back(specamt_for_7702A(0));
+ bfts_7702a.push_back(specamt_for_7702A(0).d());
}
else
{
@@ -530,7 +530,7 @@ void AccountValue::SetInitialValues()
Month = InforceMonth;
CoordinateCounters();
- DB7702A = 0.0; // TODO ?? TAXATION !! This seems silly.
+ DB7702A = currency(); // TODO ?? TAXATION !! This seems
silly.
AVRegLn = round_minutiae().c(InforceAVRegLn);
AVPrfLn = round_minutiae().c(InforceAVPrfLn);
@@ -562,21 +562,21 @@ void AccountValue::SetInitialValues()
;
}
- MaxLoan = 0.0;
+ MaxLoan = currency();
- GenAcctIntCred = 0.0;
- SepAcctIntCred = 0.0;
- RegLnIntCred = 0.0;
- PrfLnIntCred = 0.0;
+ GenAcctIntCred = currency();
+ SepAcctIntCred = currency();
+ RegLnIntCred = currency();
+ PrfLnIntCred = currency();
- MaxWD = 0.0;
- GrossWD = 0.0;
- NetWD = 0.0;
+ MaxWD = currency();
+ GrossWD = currency();
+ NetWD = currency();
CumPmts = InforceCumPmts;
TaxBasis = InforceTaxBasis;
YearlyTaxBasis.assign(BasicValues::GetLength(), currency());
- MlyNoLapsePrem = 0.0;
+ MlyNoLapsePrem = currency();
CumNoLapsePrem = InforceCumNoLapsePrem;
// Initialize all elements of this vector to 'false'. Then, when
@@ -599,7 +599,7 @@ void AccountValue::SetInitialValues()
database().query_into(DB_TermCanLapse , TermCanLapse);
TermRiderActive = true;
- TermDB = 0.0;
+ TermDB = currency();
ItLapsed = false;
@@ -628,10 +628,10 @@ void AccountValue::SetInitialValues()
}
}
- CoiCharge = 0.0;
- RiderCharges = 0.0;
- NetCoiCharge = 0.0;
- MlyDed = 0.0;
+ CoiCharge = currency();
+ RiderCharges = currency();
+ NetCoiCharge = currency();
+ MlyDed = currency();
CumulativeSalesLoad =
round_minutiae().c(yare_input_.InforceCumulativeSalesLoad);
database().query_into(DB_ExpRatCoiRetention, CoiRetentionRate);
@@ -807,29 +807,29 @@ void AccountValue::InitializeYear()
Irc7702A_->UpdateBOY7702A(Year);
}
- MonthsPolicyFees = 0.0;
- SpecAmtLoad = 0.0;
+ MonthsPolicyFees = currency();
+ SpecAmtLoad = currency();
- AssetsPostBom = 0.0;
- CumPmtsPostBom = 0.0;
- SepAcctLoad = 0.0;
+ AssetsPostBom = currency();
+ CumPmtsPostBom = currency();
+ SepAcctLoad = currency();
- YearsTotalCoiCharge = 0.0;
- YearsTotalRiderCharges = 0.0;
+ YearsTotalCoiCharge = currency();
+ YearsTotalRiderCharges = currency();
YearsAVRelOnDeath = 0.0;
YearsLoanRepaidOnDeath = 0.0;
YearsGrossClaims = 0.0;
YearsDeathProceeds = 0.0;
YearsNetClaims = 0.0;
- YearsTotalNetIntCredited = 0.0;
- YearsTotalGrossIntCredited = 0.0;
- YearsTotalLoanIntAccrued = 0.0;
+ YearsTotalNetIntCredited = currency();
+ YearsTotalGrossIntCredited = currency();
+ YearsTotalLoanIntAccrued = currency();
YearsTotalNetCoiCharge = 0.0;
- YearsTotalPolicyFee = 0.0;
+ YearsTotalPolicyFee = currency();
YearsTotalDacTaxLoad = 0.0;
- YearsTotalSpecAmtLoad = 0.0;
- YearsTotalSepAcctLoad = 0.0;
- YearsTotalGptForceout = 0.0;
+ YearsTotalSpecAmtLoad = currency();
+ YearsTotalSepAcctLoad = currency();
+ YearsTotalGptForceout = currency();
NextYearsProjectedCoiCharge = 0.0;
@@ -840,7 +840,7 @@ void AccountValue::InitializeYear()
// variable in each function might have sufficed, except that this
// quantity is used in the optional monthly detail report. Its
// value depends on the maximum loan, so it cannot be known here.
- ActualLoan = 0.0;
+ ActualLoan = currency();
GrossPmts .assign(12, currency());
EeGrossPmts .assign(12, currency());
@@ -892,7 +892,7 @@ void AccountValue::InitializeSpecAmt()
if(0 == Year)
{
- InvariantValues().InitTgtPrem = AnnualTargetPrem;
+ InvariantValues().InitTgtPrem = AnnualTargetPrem.d();
}
// TODO ?? Perform specamt strategy here?
@@ -931,8 +931,8 @@ void AccountValue::set_list_bill_premium()
,Outlay_->er_premium_modes()[Year]
,base_specamt(Year)
);
- InvariantValues().ListBillPremium = z;
- InvariantValues().ErListBillPremium = z;
+ InvariantValues().ListBillPremium = z.d();
+ InvariantValues().ErListBillPremium = z.d();
}
else
{
@@ -942,9 +942,9 @@ void AccountValue::set_list_bill_premium()
,base_specamt(Year)
,term_specamt(Year)
);
- InvariantValues().EeListBillPremium = z.first;
- InvariantValues().ErListBillPremium = z.second;
- InvariantValues().ListBillPremium = z.first + z.second;
+ InvariantValues().EeListBillPremium = z.first.d();
+ InvariantValues().ErListBillPremium = z.second.d();
+ InvariantValues().ListBillPremium = z.first.d() + z.second.d();
}
}
@@ -969,8 +969,8 @@ void AccountValue::set_modal_min_premium()
,Outlay_->er_premium_modes()[Year]
,base_specamt(Year)
);
- InvariantValues().ModalMinimumPremium[Year] = z;
- InvariantValues().ErModalMinimumPremium[Year] = z;
+ InvariantValues().ModalMinimumPremium[Year] = z.d();
+ InvariantValues().ErModalMinimumPremium[Year] = z.d();
}
else
{
@@ -980,9 +980,9 @@ void AccountValue::set_modal_min_premium()
,base_specamt(Year)
,term_specamt(Year)
);
- InvariantValues().EeModalMinimumPremium[Year] = z.first;
- InvariantValues().ErModalMinimumPremium[Year] = z.second;
- InvariantValues().ModalMinimumPremium[Year] = z.first + z.second;
+ InvariantValues().EeModalMinimumPremium[Year] = z.first.d();
+ InvariantValues().ErModalMinimumPremium[Year] = z.second.d();
+ InvariantValues().ModalMinimumPremium[Year] = z.first.d() +
z.second.d();
}
}
@@ -1145,7 +1145,7 @@ void AccountValue::SetProjectedCoiCharge()
void AccountValue::FinalizeYear()
{
- VariantValues().TotalLoanBalance[Year] = RegLnBal + PrfLnBal;
+ VariantValues().TotalLoanBalance[Year] = (RegLnBal + PrfLnBal).d();
currency total_av = TotalAccountValue();
currency surr_chg = SurrChg();
@@ -1201,12 +1201,12 @@ void AccountValue::FinalizeYear()
}
cv_7702 = std::max(cv_7702, HoneymoonValue);
- VariantValues().AcctVal [Year] = total_av;
- VariantValues().AVGenAcct [Year] = AVGenAcct + AVRegLn + AVPrfLn;
- VariantValues().AVSepAcct [Year] = AVSepAcct;
+ VariantValues().AcctVal [Year] = total_av.d();
+ VariantValues().AVGenAcct [Year] = (AVGenAcct + AVRegLn + AVPrfLn).d();
+ VariantValues().AVSepAcct [Year] = AVSepAcct.d();
VariantValues().DacTaxRsv [Year] = DacTaxRsv;
- VariantValues().CSVNet [Year] = csv_net;
- VariantValues().CV7702 [Year] = cv_7702;
+ VariantValues().CSVNet [Year] = csv_net.d();
+ VariantValues().CV7702 [Year] = cv_7702.d();
// Update death benefit. 'DBReflectingCorr' currently equals the
// death benefit as of the beginning of the twelfth month, but its
@@ -1216,11 +1216,11 @@ void AccountValue::FinalizeYear()
TxSetDeathBft();
TxSetTermAmt();
// post values to LedgerVariant
- InvariantValues().TermSpecAmt [Year] = TermSpecAmt;
- VariantValues().TermPurchased [Year] = TermDB;
+ InvariantValues().TermSpecAmt [Year] = TermSpecAmt.d();
+ VariantValues().TermPurchased [Year] = TermDB.d();
// Add term rider DB
- VariantValues().BaseDeathBft [Year] = DBReflectingCorr;
- VariantValues().EOYDeathBft [Year] = DBReflectingCorr + TermDB;
+ VariantValues().BaseDeathBft [Year] = DBReflectingCorr.d();
+ VariantValues().EOYDeathBft [Year] = (DBReflectingCorr + TermDB).d();
/*
// AV already includes any experience refund credited, but it's
@@ -1245,19 +1245,19 @@ void AccountValue::FinalizeYear()
// Monthly deduction detail
- VariantValues().COICharge [Year] = YearsTotalCoiCharge ;
- VariantValues().RiderCharges [Year] = YearsTotalRiderCharges ;
+ VariantValues().COICharge [Year] = YearsTotalCoiCharge.d() ;
+ VariantValues().RiderCharges [Year] = YearsTotalRiderCharges.d() ;
VariantValues().AVRelOnDeath [Year] = YearsAVRelOnDeath ;
VariantValues().ClaimsPaid [Year] = YearsGrossClaims ;
VariantValues().DeathProceedsPaid [Year] = YearsDeathProceeds ;
VariantValues().NetClaims [Year] = YearsNetClaims ;
- VariantValues().NetIntCredited [Year] = YearsTotalNetIntCredited ;
- VariantValues().GrossIntCredited [Year] = YearsTotalGrossIntCredited ;
- VariantValues().LoanIntAccrued [Year] = YearsTotalLoanIntAccrued ;
+ VariantValues().NetIntCredited [Year] = YearsTotalNetIntCredited.d();
+ VariantValues().GrossIntCredited [Year] = YearsTotalGrossIntCredited.d();
+ VariantValues().LoanIntAccrued [Year] = YearsTotalLoanIntAccrued.d();
VariantValues().NetCOICharge [Year] = YearsTotalNetCoiCharge ;
- VariantValues().PolicyFee [Year] = YearsTotalPolicyFee ;
+ VariantValues().PolicyFee [Year] = YearsTotalPolicyFee.d() ;
VariantValues().DacTaxLoad [Year] = YearsTotalDacTaxLoad ;
- VariantValues().SpecAmtLoad [Year] = YearsTotalSpecAmtLoad ;
+ VariantValues().SpecAmtLoad [Year] = YearsTotalSpecAmtLoad.d() ;
VariantValues().PremTaxLoad [Year] = PremiumTax_->ytd_load();
currency notional_sep_acct_charge =
@@ -1274,7 +1274,7 @@ void AccountValue::FinalizeYear()
)
;
#endif // 0
- VariantValues().SepAcctCharges [Year] = notional_sep_acct_charge ;
+ VariantValues().SepAcctCharges [Year] = notional_sep_acct_charge.d();
// Record dynamic interest rate in ledger object.
//
@@ -1311,8 +1311,8 @@ void AccountValue::FinalizeYear()
VariantValues().NetPmt[Year] = std::accumulate
(NetPmts.begin()
,NetPmts.end()
- ,-YearsTotalGptForceout
- );
+ ,currency() - YearsTotalGptForceout.d() // unary operator-()
+ ).d();
if(mce_run_gen_curr_sep_full == RunBasis_)
{
@@ -1324,15 +1324,16 @@ void AccountValue::FinalizeYear()
// Forceouts should be a distinct component, passed separately
// to ledger values. Probably we should treat 1035 exchanges
// and NAAR 'forceouts' the same way.
- InvariantValues().GrossPmt [Year] -= YearsTotalGptForceout;
- InvariantValues().EeGrossPmt[Year] -= YearsTotalGptForceout;
+ InvariantValues().GrossPmt [Year] -= YearsTotalGptForceout.d();
+ InvariantValues().EeGrossPmt[Year] -= YearsTotalGptForceout.d();
for(int j = 0; j < 12; ++j)
{
- LMI_ASSERT(materially_equal(GrossPmts[j], EeGrossPmts[j] +
ErGrossPmts[j]));
- InvariantValues().GrossPmt [Year] += GrossPmts[j];
- InvariantValues().EeGrossPmt[Year] += EeGrossPmts[j];
- InvariantValues().ErGrossPmt[Year] += ErGrossPmts[j];
+// LMI_ASSERT(materially_equal(GrossPmts[j], EeGrossPmts[j] +
ErGrossPmts[j]));
+ LMI_ASSERT(GrossPmts[j] == EeGrossPmts[j] + ErGrossPmts[j]);
+ InvariantValues().GrossPmt [Year] += GrossPmts [j].d();
+ InvariantValues().EeGrossPmt[Year] += EeGrossPmts[j].d();
+ InvariantValues().ErGrossPmt[Year] += ErGrossPmts[j].d();
}
if(0 == Year)
{
@@ -1353,7 +1354,7 @@ void AccountValue::FinalizeYear()
- InvariantValues().NewCashLoan[Year]
;
- InvariantValues().GptForceout[Year] = YearsTotalGptForceout;
+ InvariantValues().GptForceout[Year] = YearsTotalGptForceout.d();
// SOMEDAY !! Not yet implemented.
// InvariantValues().NaarForceout[Year] =
InvariantValues().ErGrossPmt[Year];
@@ -1366,8 +1367,8 @@ void AccountValue::SetAnnualInvariants()
YearsCorridorFactor = GetCorridorFactor()[Year];
YearsDBOpt = DeathBfts_->dbopt()[Year];
// policy fee should be rounded in loads class
- YearsMonthlyPolicyFee = Loads_->monthly_policy_fee(GenBasis_)[Year];
- YearsAnnualPolicyFee = Loads_->annual_policy_fee (GenBasis_)[Year];
+ YearsMonthlyPolicyFee =
currency(Loads_->monthly_policy_fee(GenBasis_)[Year]);
+ YearsAnnualPolicyFee = currency(Loads_->annual_policy_fee
(GenBasis_)[Year]);
YearsGenAcctIntRate = InterestRates_->GenAcctNetRate
(GenBasis_
diff --git a/ihs_avdebug.cpp b/ihs_avdebug.cpp
index aee9b3d..047528b 100644
--- a/ihs_avdebug.cpp
+++ b/ihs_avdebug.cpp
@@ -419,19 +419,19 @@ void AccountValue::DebugPrint()
SetMonthlyDetail(eCumNoLapsePrem ,CumNoLapsePrem );
SetMonthlyDetail(eNoLapseActive ,NoLapseActive );
SetMonthlyDetail(eEOMAV ,TotalAccountValue() );
- SetMonthlyDetail(eHMValue ,std::max<double>(HoneymoonValue,
0.0));
+ SetMonthlyDetail(eHMValue ,std::max(HoneymoonValue,
currency()));
SetMonthlyDetail(eSurrChg ,SurrChg() );
// TODO ?? Unfortunately duplicated from AccountValue::FinalizeYear().
- double total_av = TotalAccountValue();
- double csv_net =
+ currency total_av = TotalAccountValue();
+ currency csv_net =
total_av
- SurrChg()
- RegLnBal
+ GetRefundableSalesLoad()
// + std::max(0.0, ExpRatReserve) // This would be added if it
existed.
;
- csv_net = std::max<double>(HoneymoonValue, csv_net);
+ csv_net = std::max(HoneymoonValue, csv_net);
SetMonthlyDetail(eEOMCSVNet ,csv_net );
SetMonthlyDetail(eEOMCV7702 ,CashValueFor7702() );
diff --git a/ihs_avmly.cpp b/ihs_avmly.cpp
index 9ac13e5..c56f1fd 100644
--- a/ihs_avmly.cpp
+++ b/ihs_avmly.cpp
@@ -120,18 +120,18 @@ void AccountValue::DoMonthDR()
// TAXATION !! Is it really useful to comment the arguments here?
Irc7702A_->UpdateBft7702A
(Dcv
- ,DBReflectingCorr + TermDB // DB7702A
- ,OldDB // prior_db_7702A
+ ,(DBReflectingCorr + TermDB).d() // DB7702A
+ ,OldDB.d() // prior_db_7702A
,DBReflectingCorr == DBIgnoringCorr
// TAXATION !! This assumes the term rider can be treated as death
benefit;
// use 'TermIsDbFor7702A'.
- ,ActualSpecAmt + TermSpecAmt
- ,OldSA // prior_sa_7702A
- ,CashValueFor7702()
+ ,(ActualSpecAmt + TermSpecAmt).d()
+ ,OldSA.d() // prior_sa_7702A
+ ,CashValueFor7702().d()
);
- NetPmts [Month] = 0.0; // TODO ?? expunge as being unnecessary
- GrossPmts[Month] = 0.0; // TODO ?? expunge as being unnecessary
+ NetPmts [Month] = currency(); // TODO ?? expunge as being unnecessary
+ GrossPmts[Month] = currency(); // TODO ?? expunge as being unnecessary
TxExch1035();
// TODO ?? TAXATION !! Is this where spec amt should be increased by GPT?
@@ -142,7 +142,7 @@ void AccountValue::DoMonthDR()
// exchanges, but now seems unnecessary because this
// assertion never fires:
// LMI_ASSERT(kludge_account_value == Dcv);
- kludge_account_value = Dcv;
+ kludge_account_value = currency(Dcv);
}
kludge_account_value = std::max
(HoneymoonValue
@@ -153,24 +153,24 @@ void AccountValue::DoMonthDR()
// TODO ?? TAXATION !! Use CashValueFor7702() instead?
double max_necessary_premium = Irc7702A_->MaxNecessaryPremium // round
(Dcv
- ,AnnualTargetPrem
+ ,AnnualTargetPrem.d()
,YearsTotLoadTgtLowestPremtax
,YearsTotLoadExcLowestPremtax
- ,kludge_account_value
+ ,kludge_account_value.d()
);
double max_non_mec_premium = Irc7702A_->MaxNonMecPremium // round
(Dcv
- ,AnnualTargetPrem
+ ,AnnualTargetPrem.d()
,YearsTotLoadTgtLowestPremtax
,YearsTotLoadExcLowestPremtax
- ,kludge_account_value
+ ,kludge_account_value.d()
);
// Saved for monthly detail report only. TAXATION !! Then are
// these still needed...perhaps in order to report their values
// prior to accepting any payment?
- NetMaxNecessaryPremium = Irc7702A_->DebugGetNetMaxNecPm ();
- GrossMaxNecessaryPremium = Irc7702A_->DebugGetGrossMaxNecPm();
+ NetMaxNecessaryPremium = currency(Irc7702A_->DebugGetNetMaxNecPm ());
+ GrossMaxNecessaryPremium = currency(Irc7702A_->DebugGetGrossMaxNecPm());
// Determine list-bill premiums only after transactions that
// might change specamt have been processed.
@@ -187,12 +187,12 @@ void AccountValue::DoMonthDR()
{
Irc7702A_->UpdatePmt7702A
(Dcv
- ,-NetWD // TAXATION !! This should be gross, not net.
+ ,-NetWD.d() // TAXATION !! This should be gross, not net. // unary
operator-()
,false
- ,AnnualTargetPrem
+ ,AnnualTargetPrem.d()
,YearsTotLoadTgtLowestPremtax
,YearsTotLoadExcLowestPremtax
- ,kludge_account_value
+ ,kludge_account_value.d()
);
}
@@ -214,8 +214,8 @@ void AccountValue::DoMonthDR()
);
// NetMaxNecessaryPremium
// GrossMaxNecessaryPremium
- NecessaryPremium = necessary_premium;
- UnnecessaryPremium = unnecessary_premium;
+ NecessaryPremium = currency(necessary_premium );
+ UnnecessaryPremium = currency(unnecessary_premium);
if(necessary_premium < 0.0 || unnecessary_premium < 0.0)
warning()
// << GrossPmts[Month] << " GrossPmts[Month]\n"
@@ -247,7 +247,7 @@ void AccountValue::DoMonthDR()
(Dcv // Potentially modified.
,unnecessary_premium
,necessary_premium
- ,CashValueFor7702()
+ ,CashValueFor7702().d()
);
LMI_ASSERT(0.0 <= Dcv);
@@ -435,17 +435,18 @@ void AccountValue::DecrementAVProportionally(currency
decrement)
{
decrement = round_minutiae().c(decrement); // already rounded?
- if(materially_equal(decrement, AVGenAcct + AVSepAcct))
+// if(materially_equal(decrement, AVGenAcct + AVSepAcct))
+ if(decrement == AVGenAcct + AVSepAcct)
{
- AVGenAcct = 0.0;
- AVSepAcct = 0.0;
+ AVGenAcct = currency();
+ AVSepAcct = currency();
return;
}
double general_account_proportion = 0.0;
double separate_account_proportion = 0.0;
- double general_account_nonnegative_assets = std::max<double>(0.0,
AVGenAcct);
- double separate_account_nonnegative_assets = std::max<double>(0.0,
AVSepAcct);
+ double general_account_nonnegative_assets = std::max(0.0, AVGenAcct.d());
+ double separate_account_nonnegative_assets = std::max(0.0, AVSepAcct.d());
if
( 0.0 == general_account_nonnegative_assets
&& 0.0 == separate_account_nonnegative_assets
@@ -498,10 +499,11 @@ void AccountValue::DecrementAVProgressively
,oenum_increment_account_preference preferred_account
)
{
- if(materially_equal(decrement, AVGenAcct + AVSepAcct))
+// if(materially_equal(decrement, AVGenAcct + AVSepAcct))
+ if(decrement == AVGenAcct + AVSepAcct)
{
- AVGenAcct = 0.0;
- AVSepAcct = 0.0;
+ AVGenAcct = currency();
+ AVSepAcct = currency();
return;
}
@@ -554,9 +556,9 @@ void AccountValue::TxExch1035()
if(!SolvingForGuarPremium)
{
// Maybe this should return the modified value instead of altering
the argument.
- double z = GrossPmts[Month];
+ double z = GrossPmts[Month].d();
Irc7702_->ProcessGptPmt(Year, z);
- GrossPmts[Month] = z;
+ GrossPmts[Month] = currency(z);
}
// Limit external 1035 first, then internal, as necessary to avoid
// exceeding the guideline limit. This is what the customer would
@@ -592,17 +594,17 @@ void AccountValue::TxExch1035()
LMI_ASSERT(0.0 == AVSepAcct);
process_payment(NetPmts[Month]);
- DBReflectingCorr = 0.0;
+ DBReflectingCorr = currency();
TxSetDeathBft();
TxSetTermAmt();
// TODO ?? TAXATION !! Should 1035 exchanges be handled somewhere else?
LMI_ASSERT(0.0 == Dcv);
Irc7702A_->Update1035Exch7702A
(Dcv
- ,NetPmts[Month]
+ ,NetPmts[Month].d()
// TAXATION !! This assumes the term rider can be treated as death
benefit;
// use 'TermIsDbFor7702A'.
- ,ActualSpecAmt + TermSpecAmt
+ ,(ActualSpecAmt + TermSpecAmt).d()
// ,DBReflectingCorr + TermDB // TAXATION !! Alternate if 7702A benefit
is DB?
);
@@ -622,7 +624,7 @@ void AccountValue::TxExch1035()
// Immediately after a 1035 exchange, DCV should be
// the 1035 amount reduced by any premium-based loads,
// but only for the current rate basis.
- LMI_ASSERT(materially_equal(Dcv, doubleize(NetPmts[Month])));
+ LMI_ASSERT(materially_equal(Dcv, NetPmts[Month].d()));
// The initial seven-pay premium shown on the illustration
// must be its value immediately after any 1035 exchange,
@@ -633,12 +635,8 @@ void AccountValue::TxExch1035()
);
}
- LMI_ASSERT
- (materially_equal
- (GrossPmts[Month]
- ,EeGrossPmts[Month] + ErGrossPmts[Month]
- )
- );
+// LMI_ASSERT(materially_equal(GrossPmts[Month], EeGrossPmts[Month] +
ErGrossPmts[Month]));
+ LMI_ASSERT(GrossPmts[Month] == EeGrossPmts[Month] + ErGrossPmts[Month]);
}
//============================================================================
@@ -795,12 +793,12 @@ void AccountValue::ChangeSpecAmtBy(currency delta)
// TODO ?? Shouldn't this be moved to FinalizeMonth()? The problem is
// that the ledger object is used for working storage, where it should
// probably be write-only instead.
- InvariantValues().SpecAmt[j] = ActualSpecAmt;
+ InvariantValues().SpecAmt[j] = ActualSpecAmt.d();
// Adjust term here only if it's formally a rider.
// Otherwise, its amount should not have been changed.
if(!TermIsNotRider)
{
- InvariantValues().TermSpecAmt[j] = TermSpecAmt;
+ InvariantValues().TermSpecAmt[j] = TermSpecAmt.d();
}
// Term specamt is a vector in class LedgerInvariant, but a scalar in
// the input classes, e.g.:
@@ -828,7 +826,7 @@ void AccountValue::ChangeSupplAmtBy(currency delta)
// Carry the new supplemental amount forward into all future years.
for(int j = Year; j < BasicValues::GetLength(); ++j)
{
- InvariantValues().TermSpecAmt[j] = TermSpecAmt;
+ InvariantValues().TermSpecAmt[j] = TermSpecAmt.d();
}
// Reset term DB whenever term SA changes. It's not obviously
// necessary to do this here, but neither should it do any harm.
@@ -838,7 +836,7 @@ void AccountValue::ChangeSupplAmtBy(currency delta)
//============================================================================
void AccountValue::InitializeMonth()
{
- GptForceout = 0.0;
+ GptForceout = currency();
premium_load_ = 0.0;
sales_load_ = 0.0;
premium_tax_load_ = 0.0;
@@ -942,7 +940,7 @@ void AccountValue::TxOptionChange()
case mce_option2:
if(OptChgCanDecrSA)
{
- ChangeSpecAmtBy(currency(-std::max(currency(),
TotalAccountValue())));
+ ChangeSpecAmtBy(currency() - std::max(currency(),
TotalAccountValue())); // unary operator-()
}
else
{
@@ -952,7 +950,7 @@ void AccountValue::TxOptionChange()
case mce_rop:
if(OptChgCanDecrSA)
{
- ChangeSpecAmtBy(currency(-std::max(currency(), CumPmts)));
+ ChangeSpecAmtBy(currency() - std::max(currency(), CumPmts));
// unary operator-()
}
else
{
@@ -962,7 +960,7 @@ void AccountValue::TxOptionChange()
case mce_mdb:
{
// Change spec amt by its additive inverse, making it 0.
- ChangeSpecAmtBy(currency(-(ActualSpecAmt + TermSpecAmt)));
+ ChangeSpecAmtBy(currency() - (ActualSpecAmt + TermSpecAmt)); //
unary operator-()
}
break;
}
@@ -1121,8 +1119,8 @@ void AccountValue::TxTestGPT()
// use 'TermIsDbFor7702'.
bool adj_event =
(
- !materially_equal(OldSA, ActualSpecAmt + TermSpecAmt)
- && !materially_equal(OldDB, DBReflectingCorr + TermDB)
+ OldSA != ActualSpecAmt + TermSpecAmt
+ && OldDB != DBReflectingCorr + TermDB
)
|| old_dbopt != new_dbopt
;
@@ -1132,19 +1130,19 @@ void AccountValue::TxTestGPT()
// Or maybe not, because we can't match it if there was a plan change.
Irc7702_->ProcessAdjustableEvent
(Year
- ,DBReflectingCorr + TermDB
- ,OldDB
+ ,(DBReflectingCorr + TermDB).d()
+ ,OldDB.d()
// TAXATION !! This assumes the term rider can be treated as death
benefit;
// use 'TermIsDbFor7702'.
- ,ActualSpecAmt + TermSpecAmt
- ,OldSA
+ ,(ActualSpecAmt + TermSpecAmt).d()
+ ,OldSA.d()
,new_dbopt
,old_dbopt
- ,AnnualTargetPrem
+ ,AnnualTargetPrem.d()
);
}
- GptForceout = Irc7702_->Forceout();
+ GptForceout = currency(Irc7702_->Forceout());
// TODO ?? TAXATION !! On other bases, nothing is forced out, and payments
aren't limited.
process_distribution(GptForceout);
YearsTotalGptForceout += GptForceout;
@@ -1214,7 +1212,7 @@ void AccountValue::TxAscertainDesiredPayment()
return;
}
- if(!(materially_equal(GrossPmts[Month], EeGrossPmts[Month] +
ErGrossPmts[Month])))
+ if(GrossPmts[Month] != EeGrossPmts[Month] + ErGrossPmts[Month])
warning()
<< GrossPmts[Month] << " GrossPmts[Month]\n"
<< EeGrossPmts[Month] + ErGrossPmts[Month] << " EeGrossPmts[Month]
+ ErGrossPmts[Month]\n"
@@ -1224,7 +1222,8 @@ void AccountValue::TxAscertainDesiredPayment()
<< Month << " Month\n"
<< LMI_FLUSH
;
- LMI_ASSERT(materially_equal(GrossPmts[Month], EeGrossPmts[Month] +
ErGrossPmts[Month]));
+// LMI_ASSERT(materially_equal(GrossPmts[Month], EeGrossPmts[Month] +
ErGrossPmts[Month]));
+ LMI_ASSERT(GrossPmts[Month] == EeGrossPmts[Month] + ErGrossPmts[Month]);
currency eepmt {};
if(ee_pay_this_month)
@@ -1233,9 +1232,9 @@ void AccountValue::TxAscertainDesiredPayment()
// Illustration-reg guaranteed premium ignores GPT limit.
if(!SolvingForGuarPremium)
{
- double z = eepmt;
+ double z = eepmt.d();
Irc7702_->ProcessGptPmt(Year, z);
- eepmt = z;
+ eepmt = currency(z);
}
EeGrossPmts[Month] += eepmt;
GrossPmts [Month] += eepmt;
@@ -1248,15 +1247,15 @@ void AccountValue::TxAscertainDesiredPayment()
// Illustration-reg guaranteed premium ignores GPT limit.
if(!SolvingForGuarPremium)
{
- double z = erpmt;
+ double z = erpmt.d();
Irc7702_->ProcessGptPmt(Year, z);
- erpmt = z;
+ erpmt = currency(z);
}
ErGrossPmts[Month] += erpmt;
GrossPmts [Month] += erpmt;
}
- if(!(materially_equal(GrossPmts[Month], EeGrossPmts[Month] +
ErGrossPmts[Month])))
+ if(GrossPmts[Month] != EeGrossPmts[Month] + ErGrossPmts[Month])
warning()
<< GrossPmts[Month] << " GrossPmts[Month]\n"
<< EeGrossPmts[Month] + ErGrossPmts[Month] << " EeGrossPmts[Month]
+ ErGrossPmts[Month]\n"
@@ -1266,7 +1265,8 @@ void AccountValue::TxAscertainDesiredPayment()
<< Month << " Month\n"
<< LMI_FLUSH
;
- LMI_ASSERT(materially_equal(GrossPmts[Month], EeGrossPmts[Month] +
ErGrossPmts[Month]));
+// LMI_ASSERT(materially_equal(GrossPmts[Month], EeGrossPmts[Month] +
ErGrossPmts[Month]));
+ LMI_ASSERT(GrossPmts[Month] == EeGrossPmts[Month] + ErGrossPmts[Month]);
LMI_ASSERT(GrossPmts[Month] < 1.0e100);
if(0 == Year && 0 == Month)
@@ -1274,15 +1274,16 @@ void AccountValue::TxAscertainDesiredPayment()
// Illustration-reg guaranteed premium ignores GPT limit.
if(!SolvingForGuarPremium)
{
- double z = Dumpin;
+ double z = Dumpin.d();
Irc7702_->ProcessGptPmt(Year, z);
- Dumpin = z;
+ Dumpin = currency(z);
}
EeGrossPmts[Month] += Dumpin;
GrossPmts [Month] += Dumpin;
}
- if(!(materially_equal(GrossPmts[Month], EeGrossPmts[Month] +
ErGrossPmts[Month])))
+// if(!(materially_equal(GrossPmts[Month], EeGrossPmts[Month] +
ErGrossPmts[Month])))
+ if(GrossPmts[Month] != EeGrossPmts[Month] + ErGrossPmts[Month])
warning()
<< GrossPmts[Month] << " GrossPmts[Month]\n"
<< EeGrossPmts[Month] + ErGrossPmts[Month] << " EeGrossPmts[Month]
+ ErGrossPmts[Month]\n"
@@ -1292,7 +1293,8 @@ void AccountValue::TxAscertainDesiredPayment()
<< Month << " Month\n"
<< LMI_FLUSH
;
- LMI_ASSERT(materially_equal(GrossPmts[Month], EeGrossPmts[Month] +
ErGrossPmts[Month]));
+// LMI_ASSERT(materially_equal(GrossPmts[Month], EeGrossPmts[Month] +
ErGrossPmts[Month]));
+ LMI_ASSERT(GrossPmts[Month] == EeGrossPmts[Month] + ErGrossPmts[Month]);
}
/// Limit payment (e.g., to the non-MEC maximum).
@@ -1312,7 +1314,8 @@ void AccountValue::TxLimitPayment(double a_maxpmt)
// we shouldn't.
// TODO ?? TAXATION !! Clean this up, and put GPT limit here, on prem net of
WD.
- if(!(materially_equal(GrossPmts[Month], EeGrossPmts[Month] +
ErGrossPmts[Month])))
+ if(GrossPmts[Month] != EeGrossPmts[Month] + ErGrossPmts[Month])
+// if(!(materially_equal(GrossPmts[Month], EeGrossPmts[Month] +
ErGrossPmts[Month])))
warning()
<< GrossPmts[Month] << " GrossPmts[Month]\n"
<< EeGrossPmts[Month] + ErGrossPmts[Month] << " EeGrossPmts[Month]
+ ErGrossPmts[Month]\n"
@@ -1322,7 +1325,8 @@ void AccountValue::TxLimitPayment(double a_maxpmt)
<< Month << " Month\n"
<< LMI_FLUSH
;
- LMI_ASSERT(materially_equal(GrossPmts[Month], EeGrossPmts[Month] +
ErGrossPmts[Month]));
+// LMI_ASSERT(materially_equal(GrossPmts[Month], EeGrossPmts[Month] +
ErGrossPmts[Month]));
+ LMI_ASSERT(GrossPmts[Month] == EeGrossPmts[Month] + ErGrossPmts[Month]);
if(mce_reduce_prem == yare_input_.AvoidMecMethod &&
!Irc7702A_->IsMecAlready())
{
@@ -1332,7 +1336,7 @@ void AccountValue::TxLimitPayment(double a_maxpmt)
gross_1035 = External1035Amount + Internal1035Amount;
}
currency gross_pmt_without_1035 = GrossPmts[Month] - gross_1035;
- gross_pmt_without_1035 = std::min<double>(gross_pmt_without_1035,
a_maxpmt);
+ gross_pmt_without_1035 = currency(std::min(gross_pmt_without_1035.d(),
a_maxpmt));
// TODO ?? For now at least, reduce employee premium first.
progressively_limit
(EeGrossPmts[Month]
@@ -1346,7 +1350,8 @@ void AccountValue::TxLimitPayment(double a_maxpmt)
GrossPmts[Month] = EeGrossPmts[Month] + ErGrossPmts[Month];
}
- LMI_ASSERT(materially_equal(GrossPmts[Month], EeGrossPmts[Month] +
ErGrossPmts[Month]));
+// LMI_ASSERT(materially_equal(GrossPmts[Month], EeGrossPmts[Month] +
ErGrossPmts[Month]));
+ LMI_ASSERT(GrossPmts[Month] == EeGrossPmts[Month] + ErGrossPmts[Month]);
if(Solving || mce_run_gen_curr_sep_full == RunBasis_)
{
@@ -1360,12 +1365,8 @@ void AccountValue::TxLimitPayment(double a_maxpmt)
GrossPmts[Month] = EeGrossPmts[Month] + ErGrossPmts[Month];
}
- LMI_ASSERT
- (materially_equal
- (GrossPmts[Month]
- ,EeGrossPmts[Month] + ErGrossPmts[Month]
- )
- );
+// LMI_ASSERT(materially_equal(GrossPmts[Month], EeGrossPmts[Month] +
ErGrossPmts[Month]));
+ LMI_ASSERT(GrossPmts[Month] == EeGrossPmts[Month] + ErGrossPmts[Month]);
}
//============================================================================
@@ -1386,7 +1387,7 @@ void AccountValue::TxRecognizePaymentFor7702A
currency kludge_account_value = std::max(TotalAccountValue(),
HoneymoonValue);
if(0 == Year && 0 == Month)
{
- kludge_account_value = Dcv;
+ kludge_account_value = currency(Dcv);
}
kludge_account_value = std::max
(HoneymoonValue
@@ -1402,12 +1403,12 @@ void AccountValue::TxRecognizePaymentFor7702A
currency amount_paid_7702A = a_pmt;
Irc7702A_->UpdatePmt7702A
(Dcv
- ,amount_paid_7702A
+ ,amount_paid_7702A.d()
,a_this_payment_is_unnecessary
- ,AnnualTargetPrem
+ ,AnnualTargetPrem.d()
,YearsTotLoadTgtLowestPremtax
,YearsTotLoadExcLowestPremtax
- ,kludge_account_value
+ ,kludge_account_value.d()
);
}
@@ -1443,7 +1444,7 @@ void AccountValue::TxAcceptPayment(currency a_pmt)
process_payment(net_pmt);
- Dcv += std::max(currency(), net_pmt);
+ Dcv += std::max(0.0, net_pmt.d());
LMI_ASSERT(0.0 <= Dcv);
if(HoneymoonActive)
@@ -1489,7 +1490,7 @@ currency AccountValue::GetPremLoad
{
currency excess_portion;
// All excess.
- if(0.0 == UnusedTargetPrem)
+ if(currency() == UnusedTargetPrem)
{
excess_portion = a_pmt;
}
@@ -1497,12 +1498,12 @@ currency AccountValue::GetPremLoad
else if(UnusedTargetPrem < a_pmt)
{
excess_portion = a_pmt - UnusedTargetPrem;
- UnusedTargetPrem = 0.0;
+ UnusedTargetPrem = currency();
}
// All target.
else
{
- excess_portion = 0.0;
+ excess_portion = currency();
UnusedTargetPrem -= a_pmt;
}
currency target_portion = a_pmt - excess_portion;
@@ -1520,7 +1521,7 @@ currency AccountValue::GetPremLoad
CumulativeSalesLoad += sales_load_;
premium_tax_load_ = PremiumTax_->calculate_load
- (a_pmt - a_portion_exempt_from_premium_tax
+ ((a_pmt - a_portion_exempt_from_premium_tax).d()
,*StratifiedCharges_
);
@@ -1582,16 +1583,16 @@ void AccountValue::TxLoanRepay()
// TODO ?? This idiom seems too cute. And it can return -0.0 .
// Maximum repayment is total debt.
- ActualLoan = -std::min(-RequestedLoan, doubleize(RegLnBal) +
doubleize(PrfLnBal));
+ ActualLoan = currency() - std::min(currency() - RequestedLoan, RegLnBal +
PrfLnBal); // unary operator-()
process_distribution(ActualLoan);
- LMI_ASSERT(0.0 == progressively_reduce(AVRegLn , AVPrfLn ,
currency(-ActualLoan)));
- LMI_ASSERT(0.0 == progressively_reduce(RegLnBal, PrfLnBal,
currency(-ActualLoan)));
+ LMI_ASSERT(0.0 == progressively_reduce(AVRegLn , AVPrfLn , currency() -
ActualLoan)); // unary operator-()
+ LMI_ASSERT(0.0 == progressively_reduce(RegLnBal, PrfLnBal, currency() -
ActualLoan)); // unary operator-()
// This seems wrong. If we're changing something that's invariant among
// bases, why do we change it for each basis?
// TODO ?? Shouldn't this be moved to FinalizeMonth()?
- InvariantValues().NewCashLoan[Year] = ActualLoan;
+ InvariantValues().NewCashLoan[Year] = ActualLoan.d();
// TODO ?? Consider changing loan_ullage_[Year] here.
}
@@ -1619,7 +1620,7 @@ void AccountValue::TxSetBOMAV()
? std::max
(term_specamt(0) + base_specamt(0)
,round_death_benefit().c(NetPmts[0] *
YearsCorridorFactor)
- )
+ ).d()
: yare_input_.InforceSpecAmtLoadBase
)
);
@@ -1639,7 +1640,7 @@ void AccountValue::TxSetBOMAV()
process_deduction(MonthsPolicyFees + SpecAmtLoad);
- Dcv -= MonthsPolicyFees + SpecAmtLoad;
+ Dcv -= (MonthsPolicyFees + SpecAmtLoad).d();
Dcv = std::max(0.0, Dcv);
}
@@ -1705,12 +1706,12 @@ void AccountValue::TxSetDeathBft()
// Specamt is a floor under DB (and therefore zero here)
// because this option defines the DB as the minimum
// required by the corridor (but not less than zero).
- DBIgnoringCorr = 0.0;
- DB7702A = 0.0;
+ DBIgnoringCorr = currency();
+ DB7702A = currency();
}
break;
}
- LMI_ASSERT(0.0 <= DBIgnoringCorr);
+ LMI_ASSERT(currency() <= DBIgnoringCorr);
// Surrender charges are generally ignored here, but any negative
// surrender charge must be subtracted, increasing the account value.
@@ -1737,8 +1738,8 @@ void AccountValue::TxSetDeathBft()
// TAXATION !! Use DB_Irc7702BftIsSpecAmt
DB7702A = DBReflectingCorr + TermDB;
- DcvDeathBft = std::max<double>
- (DBIgnoringCorr
+ DcvDeathBft = std::max
+ (DBIgnoringCorr.d()
, (
YearsCorridorFactor
* ( Dcv
@@ -1808,12 +1809,12 @@ void AccountValue::EndTermRider(bool convert)
{
ChangeSpecAmtBy(TermSpecAmt);
}
- TermSpecAmt = 0.0;
- TermDB = 0.0;
+ TermSpecAmt = currency();
+ TermDB = currency();
// Carry the new term spec amt forward into all future years.
for(int j = Year; j < BasicValues::GetLength(); ++j)
{
- InvariantValues().TermSpecAmt[j] = TermSpecAmt;
+ InvariantValues().TermSpecAmt[j] = TermSpecAmt.d();
}
}
@@ -1843,7 +1844,7 @@ void AccountValue::TxSetCoiCharge()
// TAXATION !! Should this be handled at the same time as GPT forceouts?
DcvNaar = material_difference
- (std::max<double>(DcvDeathBft, DBIgnoringCorr) * DBDiscountRate[Year]
+ (std::max<double>(DcvDeathBft, DBIgnoringCorr.d()) *
DBDiscountRate[Year]
,std::max(0.0, Dcv)
);
// DCV need not be rounded.
@@ -1888,15 +1889,15 @@ void AccountValue::TxSetCoiCharge()
void AccountValue::TxSetRiderDed()
{
- AdbCharge = 0.0;
+ AdbCharge = currency();
if(yare_input_.AccidentalDeathBenefit)
{
AdbCharge = round_rider_charges().c
- (YearsAdbRate * std::min<double>(ActualSpecAmt, AdbLimit)
+ (YearsAdbRate * std::min(ActualSpecAmt.d(), AdbLimit)
);
}
- SpouseRiderCharge = 0.0;
+ SpouseRiderCharge = currency();
if(yare_input_.SpouseRider)
{
SpouseRiderCharge = round_rider_charges().c
@@ -1904,7 +1905,7 @@ void AccountValue::TxSetRiderDed()
);
}
- ChildRiderCharge = 0.0;
+ ChildRiderCharge = currency();
if(yare_input_.ChildRider)
{
ChildRiderCharge = round_rider_charges().c
@@ -1912,7 +1913,7 @@ void AccountValue::TxSetRiderDed()
);
}
- TermCharge = 0.0;
+ TermCharge = currency();
DcvTermCharge = 0.0;
if(TermRiderActive)
{
@@ -1926,7 +1927,7 @@ void AccountValue::TxSetRiderDed()
DcvTermCharge = YearsDcvCoiRate * TermDB * DBDiscountRate[Year];
}
- WpCharge = 0.0;
+ WpCharge = currency();
DcvWpCharge = 0.0;
if(yare_input_.WaiverOfPremiumBenefit)
{
@@ -1935,9 +1936,9 @@ void AccountValue::TxSetRiderDed()
case oe_waiver_times_specamt:
{
WpCharge = round_rider_charges().c
- (YearsWpRate * std::min<double>(ActualSpecAmt, WpLimit)
+ (YearsWpRate * std::min(ActualSpecAmt.d(), WpLimit)
);
- DcvWpCharge = WpCharge;
+ DcvWpCharge = WpCharge.d();
}
break;
case oe_waiver_times_deductions:
@@ -1981,11 +1982,11 @@ void AccountValue::TxDoMlyDed()
if(TermRiderActive && TermCanLapse && (AVGenAcct + AVSepAcct - CoiCharge)
< TermCharge)
{
EndTermRider(false);
- TermCharge = 0.0;
+ TermCharge = currency();
}
// 'Simple' riders are the same for AV and DCV.
- double simple_rider_charges =
+ currency simple_rider_charges =
AdbCharge
+ SpouseRiderCharge
+ ChildRiderCharge
@@ -1993,7 +1994,7 @@ void AccountValue::TxDoMlyDed()
double dcv_mly_ded =
DcvCoiCharge
- + simple_rider_charges
+ + simple_rider_charges.d()
+ DcvTermCharge
+ DcvWpCharge
;
@@ -2014,7 +2015,7 @@ void AccountValue::TxDoMlyDed()
// determined.
MlyDed += MonthsPolicyFees + SpecAmtLoad;
- YearsTotalNetCoiCharge += NetCoiCharge;
+ YearsTotalNetCoiCharge += NetCoiCharge.d();
SepAcctValueAfterDeduction = AVSepAcct;
}
@@ -2072,15 +2073,15 @@ void AccountValue::TxTakeSepAcctLoad()
{
double stratified_load = StratifiedCharges_->stratified_sepacct_load
(GenBasis_
- ,AssetsPostBom
- ,CumPmtsPostBom
+ ,AssetsPostBom.d()
+ ,CumPmtsPostBom.d()
,database().query<double>(DB_DynSepAcctLoadLimit)
);
double tiered_comp = 0.0;
if(oe_asset_charge_load ==
database().query<oenum_asset_charge_type>(DB_AssetChargeType))
{
- tiered_comp =
StratifiedCharges_->tiered_asset_based_compensation(AssetsPostBom);
+ tiered_comp =
StratifiedCharges_->tiered_asset_based_compensation(AssetsPostBom.d());
}
if(0.0 != tiered_comp)
{
@@ -2107,7 +2108,7 @@ void AccountValue::TxTakeSepAcctLoad()
SepAcctLoad = round_interest_credit().c(YearsSepAcctLoadRate * AVSepAcct);
process_deduction(SepAcctLoad);
YearsTotalSepAcctLoad += SepAcctLoad;
- Dcv -= SepAcctLoad;
+ Dcv -= SepAcctLoad.d();
Dcv = std::max(0.0, Dcv);
}
@@ -2148,8 +2149,8 @@ void AccountValue::ApplyDynamicMandE(currency assets)
// Annual separate-account rates.
- double m_and_e_rate = StratifiedCharges_->tiered_m_and_e(GenBasis_,
assets);
- double imf_rate =
StratifiedCharges_->tiered_investment_management_fee(assets);
+ double m_and_e_rate = StratifiedCharges_->tiered_m_and_e(GenBasis_,
assets.d());
+ double imf_rate =
StratifiedCharges_->tiered_investment_management_fee(assets.d());
if(0.0 != imf_rate)
{
alarum()
@@ -2159,7 +2160,7 @@ void AccountValue::ApplyDynamicMandE(currency assets)
}
double asset_comp_rate =
(oe_asset_charge_spread ==
database().query<oenum_asset_charge_type>(DB_AssetChargeType))
- ? StratifiedCharges_->tiered_asset_based_compensation(assets)
+ ? StratifiedCharges_->tiered_asset_based_compensation(assets.d())
: 0.0
;
if(0.0 != asset_comp_rate)
@@ -2226,25 +2227,25 @@ void AccountValue::TxCreditInt()
if(0.0 < AVSepAcct)
{
SepAcctIntCred = InterestCredited(AVSepAcct, YearsSepAcctIntRate);
- double gross = InterestCredited(AVSepAcct, gross_sep_acct_rate);
- notional_sep_acct_charge = gross - SepAcctIntCred;
+ double gross = InterestCredited(AVSepAcct, gross_sep_acct_rate).d();
+ notional_sep_acct_charge = (gross - SepAcctIntCred).d();
// Guard against catastrophic cancellation. Testing the
// absolute values of the addends for material equality is not
// sufficient, because the interest increment has already been
// rounded.
- double result = AVSepAcct + SepAcctIntCred;
+ double result = (AVSepAcct + SepAcctIntCred).d();
if(result < 0.0 && 0.0 <= AVSepAcct)
{
- AVSepAcct = 0.0;
+ AVSepAcct = currency();
}
else
{
- AVSepAcct = result;
+ AVSepAcct = currency(result);
}
}
else
{
- SepAcctIntCred = 0.0;
+ SepAcctIntCred = currency();
}
if(0.0 < AVGenAcct)
@@ -2268,7 +2269,7 @@ void AccountValue::TxCreditInt()
}
else
{
- GenAcctIntCred = 0.0;
+ GenAcctIntCred = currency();
}
LMI_ASSERT(0.0 <= Dcv);
@@ -2299,11 +2300,11 @@ void AccountValue::TxLoanInt()
{
// Reinitialize to zero before potential early exit, to sweep away
// any leftover values (e.g., after a loan has been paid off).
- RegLnIntCred = 0.0;
- PrfLnIntCred = 0.0;
+ RegLnIntCred = currency();
+ PrfLnIntCred = currency();
// Nothing more to do if there's no loan outstanding.
- if(0.0 == RegLnBal && 0.0 == PrfLnBal)
+ if(currency() == RegLnBal && 0.0 == PrfLnBal)
{
return;
}
@@ -2316,8 +2317,8 @@ void AccountValue::TxLoanInt()
AVRegLn += RegLnIntCred;
AVPrfLn += PrfLnIntCred;
- double RegLnIntAccrued = InterestCredited(RegLnBal, YearsRegLnIntDueRate);
- double PrfLnIntAccrued = InterestCredited(PrfLnBal, YearsPrfLnIntDueRate);
+ currency RegLnIntAccrued = InterestCredited(RegLnBal,
YearsRegLnIntDueRate);
+ currency PrfLnIntAccrued = InterestCredited(PrfLnBal,
YearsPrfLnIntDueRate);
RegLnBal += RegLnIntAccrued;
PrfLnBal += PrfLnIntAccrued;
@@ -2409,7 +2410,7 @@ void AccountValue::TxTakeWD()
return;
}
- GrossWD = 0.0;
+ GrossWD = currency();
RequestedWD = Outlay_->withdrawals()[Year];
if(Debugging || 0.0 != RequestedWD)
@@ -2417,12 +2418,12 @@ void AccountValue::TxTakeWD()
SetMaxWD();
}
- NetWD = 0.0;
+ NetWD = currency();
// Nothing more to do if no withdrawal requested.
if(0.0 == RequestedWD)
{
- withdrawal_ullage_[Year] = 0.0;
+ withdrawal_ullage_[Year] = currency();
// This seems wrong. If we're changing something that's invariant among
// bases, why do we change it for each basis?
// TODO ?? Shouldn't this be moved to FinalizeMonth()?
@@ -2460,8 +2461,8 @@ void AccountValue::TxTakeWD()
// Impose minimum amount on withdrawals.
if(RequestedWD < MinWD)
{
- withdrawal_ullage_[Year] = 0.0;
- NetWD = 0.0;
+ withdrawal_ullage_[Year] = currency();
+ NetWD = currency();
}
// TODO ?? If WD zero, skip some steps? Cannot simply return in this case
// because user may prefer to shift to loans.
@@ -2482,10 +2483,10 @@ void AccountValue::TxTakeWD()
// Even after the entire basis has been withdrawn, we still
// take withdrawals if payments since have increased the basis.
// TODO ?? Should RequestedWD be constrained by MaxWD and MinWD here?
- if(0.0 == TaxBasis || std::min(TaxBasis, RequestedWD) < MinWD) // All
loan
+ if(currency() == TaxBasis || std::min(TaxBasis, RequestedWD) < MinWD)
// All loan
{
- withdrawal_ullage_[Year] = 0.0;
- NetWD = 0.0;
+ withdrawal_ullage_[Year] = currency();
+ NetWD = currency();
}
else if(NetWD < TaxBasis) // All WD
{
@@ -2567,7 +2568,7 @@ void AccountValue::TxTakeWD()
return;
}
- GrossWD = round_withdrawal().c(NetWD + std::min<double>(WDFee, NetWD *
WDFeeRate));
+ GrossWD = round_withdrawal().c(NetWD.d() + std::min(WDFee.d(), NetWD *
WDFeeRate));
// Free partial surrenders: for instance, the first 20% of account
// value might be withdrawn each policy year free of surrender
@@ -2585,13 +2586,13 @@ void AccountValue::TxTakeWD()
LMI_ASSERT(AVPrfLn == PrfLnBal);
LMI_ASSERT(av == AVGenAcct + AVSepAcct);
double free_wd = FreeWDProportion[Year] * av;
- non_free_wd = std::max(0.0, doubleize(GrossWD) - free_wd);
+ non_free_wd = currency(std::max(0.0, GrossWD.d() - free_wd));
}
double partial_surrchg = non_free_wd * surrchg_proportion;
GrossWD += round_withdrawal().c(partial_surrchg);
process_distribution(GrossWD);
- Dcv -= GrossWD;
+ Dcv -= GrossWD.d();
Dcv = std::max(0.0, Dcv);
switch(YearsDBOpt)
@@ -2673,7 +2674,7 @@ void AccountValue::TxTakeWD()
{
// TODO ?? TAXATION !! What if reference argument
// 'premiums_paid_increment' is modified?
- double premiums_paid_increment = -GrossWD;
+ double premiums_paid_increment = 0.0 - GrossWD.d(); // unary
operator-()
Irc7702_->ProcessGptPmt(Year, premiums_paid_increment);
}
}
@@ -2681,7 +2682,7 @@ void AccountValue::TxTakeWD()
// This seems wrong. If we're changing something that's invariant among
// bases, why do we change it for each basis?
// TODO ?? Shouldn't this be moved to FinalizeMonth()?
- InvariantValues().NetWD[Year] = NetWD;
+ InvariantValues().NetWD[Year] = NetWD.d();
}
//============================================================================
@@ -2689,10 +2690,10 @@ void AccountValue::TxTakeWD()
void AccountValue::SetMaxLoan()
{
double max_loan =
- (AVGenAcct + AVSepAcct) * MaxLoanAVMult
- + (AVRegLn + AVPrfLn)
- - anticipated_deduction(MaxLoanDed_)
- - std::max(currency(), SurrChg())
+ (AVGenAcct + AVSepAcct).d() * MaxLoanAVMult
+ + (AVRegLn + AVPrfLn).d()
+ - anticipated_deduction(MaxLoanDed_).d()
+ - std::max(currency(), SurrChg()).d()
;
// Illustrations generally permit loans only on anniversary.
@@ -2764,9 +2765,9 @@ void AccountValue::TxTakeLoan()
}
// Nothing more to do if no loan requested.
- if(RequestedLoan <= 0.0)
+ if(RequestedLoan <= currency())
{
- loan_ullage_[Year] = 0.0;
+ loan_ullage_[Year] = currency();
return;
}
@@ -2785,7 +2786,7 @@ void AccountValue::TxTakeLoan()
ActualLoan = std::min(max_loan_increment, RequestedLoan);
ActualLoan = std::max(ActualLoan, currency());
// TODO ?? Shouldn't this happen in FinalizeMonth()?
- InvariantValues().NewCashLoan[Year] = ActualLoan;
+ InvariantValues().NewCashLoan[Year] = ActualLoan.d();
}
{
@@ -2875,7 +2876,8 @@ void AccountValue::TxTestLapse()
( NoLapseMinAge <= Year + BasicValues::GetIssueAge()
&& NoLapseMinDur <= Year
|| CumPmts < CumNoLapsePrem
- && !materially_equal(CumPmts, CumNoLapsePrem)
+// && !materially_equal(CumPmts, CumNoLapsePrem)
+ && CumPmts != CumNoLapsePrem
)
{
NoLapseActive = false;
@@ -2936,8 +2938,8 @@ void AccountValue::TxTestLapse()
{
if(NoLapseActive && lapse_test_csv < 0.0)
{
- AVGenAcct = 0.0;
- AVSepAcct = 0.0;
+ AVGenAcct = currency();
+ AVSepAcct = currency();
// TODO ?? Can't this be done elsewhere?
VariantValues().CSVNet[Year] = 0.0;
}
@@ -2960,9 +2962,9 @@ void AccountValue::FinalizeMonth()
{
if(0 == Year && 0 == Month)
{
- InvariantValues().External1035Amount = External1035Amount;
- InvariantValues().Internal1035Amount = Internal1035Amount;
- InvariantValues().Dumpin = Dumpin;
+ InvariantValues().External1035Amount = External1035Amount.d();
+ InvariantValues().Internal1035Amount = Internal1035Amount.d();
+ InvariantValues().Dumpin = Dumpin.d();
}
// TAXATION !! We could also capture MEC status on other bases here.
diff --git a/ihs_avsolve.cpp b/ihs_avsolve.cpp
index c4e5396..b22c769 100644
--- a/ihs_avsolve.cpp
+++ b/ihs_avsolve.cpp
@@ -67,7 +67,7 @@ class SolveHelper
// double operator()(currency a_CandidateValue)
double operator()(double a_CandidateValue)
{
- return av.SolveTest(currency(a_CandidateValue));
+ return av.SolveTest(currency(a_CandidateValue)).d();
}
};
@@ -184,9 +184,11 @@ currency AccountValue::SolveTest(currency a_CandidateValue)
currency most_negative_csv(0.0);
if(no_lapse_dur < SolveTargetDuration_)
{
- most_negative_csv = *std::min_element
- (VariantValues().CSVNet.begin() + no_lapse_dur
- ,VariantValues().CSVNet.begin() + SolveTargetDuration_
+ most_negative_csv = currency
+ (*std::min_element
+ (VariantValues().CSVNet.begin() + no_lapse_dur
+ ,VariantValues().CSVNet.begin() + SolveTargetDuration_
+ )
);
}
@@ -206,7 +208,7 @@ currency AccountValue::SolveTest(currency a_CandidateValue)
);
currency worst_negative = std::min
(most_negative_csv
- ,currency(-greatest_ullage) // really want a unary-negation operator
+ ,currency() - greatest_ullage // really want a unary-negation operator
);
// SolveTargetDuration_ is in origin one. That's natural for loop
@@ -215,10 +217,11 @@ currency AccountValue::SolveTest(currency
a_CandidateValue)
currency value = currency(VariantValues().CSVNet[SolveTargetDuration_ -
1]);
if(mce_solve_for_target_naar == SolveTarget_)
{
- value =
+ value = currency
+ (
VariantValues().EOYDeathBft[SolveTargetDuration_ - 1]
- VariantValues().AcctVal [SolveTargetDuration_ - 1]
- ;
+ );
}
if(worst_negative < 0.0)
{
@@ -370,7 +373,7 @@ currency AccountValue::Solve
( 0 == SolveBeginYear_
&& yare_input_.EffectiveDate == yare_input_.InforceAsOfDate
,false
- );
+ ).d();
}
break;
case mce_solve_ee_prem:
diff --git a/ihs_avstrtgy.cpp b/ihs_avstrtgy.cpp
index 27eb18a..fb3197f 100644
--- a/ihs_avstrtgy.cpp
+++ b/ihs_avstrtgy.cpp
@@ -147,8 +147,9 @@ void AccountValue::PerformSpecAmtStrategy()
strategy = mce_sa_input_scalar;
}
currency z = CalculateSpecAmtFromStrategy(j, 0, explicit_value,
strategy);
- // Shouldn't rounding be done upstream?
- DeathBfts_->set_specamt(currency(round_specamt()(std::max(m, z))), j,
1 + j);
+ // Shouldn't rounding be done upstream? Was it?
+ DeathBfts_->set_specamt(currency(std::max(m, z)), j, 1 + j); //
round(currency)?
+// DeathBfts_->set_specamt(currency(round_specamt()(std::max(m, z))), j,
1 + j); // round(currency)?
if
( j == InforceYear
&& yare_input_.EffectiveDate != yare_input_.InforceAsOfDate
@@ -179,8 +180,9 @@ void AccountValue::PerformSupplAmtStrategy()
currency explicit_value = DeathBfts_->supplamt()[j];
mcenum_sa_strategy strategy =
yare_input_.SupplementalAmountStrategy[j];
currency z = CalculateSpecAmtFromStrategy(j, 0, explicit_value,
strategy);
- // Shouldn't rounding be done upstream?
- DeathBfts_->set_supplamt(currency(round_specamt()(std::max(m, z))), j,
1 + j);
+ // Shouldn't rounding be done upstream? Was it?
+// DeathBfts_->set_supplamt(currency(round_specamt()(std::max(m, z))), j,
1 + j); // round(currency)?
+ DeathBfts_->set_supplamt(currency(std::max(m, z)), j, 1 + j); //
round(currency)?
}
}
diff --git a/ihs_basicval.cpp b/ihs_basicval.cpp
index 9b2702f..2b79304 100644
--- a/ihs_basicval.cpp
+++ b/ihs_basicval.cpp
@@ -565,7 +565,7 @@ void BasicValues::Init7702()
/// These loads should instead reflect the lowest premium-tax rate.
,Loads_->target_premium_load_excluding_premium_tax()
,Loads_->excess_premium_load_excluding_premium_tax()
- ,InitialTargetPremium
+ ,InitialTargetPremium.d()
,round_min_premium()
,round_max_premium()
,round_min_specamt()
@@ -614,10 +614,10 @@ currency BasicValues::GetAnnualTgtPrem(int a_year,
currency a_specamt) const
void BasicValues::SetPermanentInvariants()
{
// maybe implement query_into<currency>
- MinIssSpecAmt = database().query<int>(DB_MinIssSpecAmt);
- MinIssBaseSpecAmt = database().query<int>(DB_MinIssBaseSpecAmt);
- MinRenlSpecAmt = database().query<int>(DB_MinRenlSpecAmt);
- MinRenlBaseSpecAmt = database().query<int>(DB_MinRenlBaseSpecAmt);
+ MinIssSpecAmt = currency(database().query<int>(DB_MinIssSpecAmt
));
+ MinIssBaseSpecAmt = currency(database().query<int>(DB_MinIssBaseSpecAmt
));
+ MinRenlSpecAmt = currency(database().query<int>(DB_MinRenlSpecAmt
));
+ MinRenlBaseSpecAmt =
currency(database().query<int>(DB_MinRenlBaseSpecAmt));
database().query_into(DB_NoLapseDboLvlOnly , NoLapseDboLvlOnly);
database().query_into(DB_NoLapseUnratedOnly , NoLapseUnratedOnly);
database().query_into(DB_DboChgCanIncrSpecAmt , OptChgCanIncrSA);
@@ -635,7 +635,7 @@ void BasicValues::SetPermanentInvariants()
database().query_into(DB_MinPremType , MinPremType);
database().query_into(DB_TgtPremType , TgtPremType);
database().query_into(DB_TgtPremFixedAtIssue , TgtPremFixedAtIssue);
- TgtPremMonthlyPolFee = database().query<int>(DB_TgtPremMonthlyPolFee);
+ TgtPremMonthlyPolFee =
currency(database().query<int>(DB_TgtPremMonthlyPolFee));
// Assertion: see comments on GetModalPremTgtFromTable().
LMI_ASSERT(0.0 == TgtPremMonthlyPolFee || oe_modal_table == TgtPremType);
database().query_into(DB_CurrCoiTable0Limit , CurrCoiTable0Limit);
@@ -661,8 +661,8 @@ void BasicValues::SetPermanentInvariants()
// AdbLimit = database().query<int>(DB_AdbLimit );
// WpLimit = database().query<int>(DB_WpLimit );
// SpecAmtLoadLimit = database().query<int>(DB_SpecAmtLoadLimit);
- MinWD = database().query<int>(DB_MinWd );
- WDFee = database().query<int>(DB_WdFee );
+ MinWD = currency(database().query<int>(DB_MinWd ));
+ WDFee = currency(database().query<int>(DB_WdFee ));
database().query_into(DB_WdFeeRate , WDFeeRate);
database().query_into(DB_AllowChangeToDbo2 , AllowChangeToDBO2);
database().query_into(DB_AllowSpecAmtIncr , AllowSAIncr);
@@ -770,7 +770,7 @@ void BasicValues::SetPermanentInvariants()
database().query_into(DB_Effective7702DboRop, Effective7702DboRop);
TermIsDbFor7702 = oe_7702_term_is_db ==
database().query<oenum_7702_term>(DB_TermIsQABOrDb7702 );
TermIsDbFor7702A = oe_7702_term_is_db ==
database().query<oenum_7702_term>(DB_TermIsQABOrDb7702A);
- MaxNAAR = yare_input_.MaximumNaar;
+ MaxNAAR = currency(yare_input_.MaximumNaar);
database().query_into(DB_MinPremIntSpread, MinPremIntSpread_);
}
@@ -1083,8 +1083,8 @@ currency BasicValues::GetModalPremGLP
// for GPT reimplementation.
double z = Irc7702_->CalculateGLP
(a_duration
- ,a_bft_amt
- ,a_specamt
+ ,a_bft_amt.d()
+ ,a_specamt.d()
,Irc7702_->GetLeastBftAmtEver()
,effective_dbopt_7702(DeathBfts_->dbopt()[0], Effective7702DboRop)
);
@@ -1107,8 +1107,8 @@ currency BasicValues::GetModalPremGSP
{
double z = Irc7702_->CalculateGSP
(a_duration
- ,a_bft_amt
- ,a_specamt
+ ,a_bft_amt.d()
+ ,a_specamt.d()
,Irc7702_->GetLeastBftAmtEver()
);
@@ -1203,7 +1203,7 @@ std::pair<double,double> BasicValues::approx_mly_ded
if(yare_input_.AccidentalDeathBenefit)
{
double const r = MortalityRates_->AdbRates()[year];
- mly_ded += r * std::min<double>(specamt, AdbLimit);
+ mly_ded += r * std::min(specamt.d(), AdbLimit);
}
if(yare_input_.SpouseRider)
@@ -1221,7 +1221,7 @@ std::pair<double,double> BasicValues::approx_mly_ded
if(true) // Written thus for parallelism and to keep 'r' local.
{
double const r = Loads_->specified_amount_load(mce_gen_curr)[year];
- mly_ded += r * std::min<double>(specamt, SpecAmtLoadLimit);
+ mly_ded += r * std::min(specamt.d(), SpecAmtLoadLimit);
}
mly_ded += Loads_->monthly_policy_fee(mce_gen_curr)[year];
@@ -1235,7 +1235,7 @@ std::pair<double,double> BasicValues::approx_mly_ded
{
case oe_waiver_times_specamt:
{
- mly_ded += r * std::min<double>(specamt, WpLimit);
+ mly_ded += r * std::min(specamt.d(), WpLimit);
}
break;
case oe_waiver_times_deductions:
@@ -1291,7 +1291,7 @@ std::pair<double,double> BasicValues::approx_mly_ded_ex
if(yare_input_.AccidentalDeathBenefit)
{
double const r = MortalityRates_->AdbRates()[year];
- er_ded += r * std::min<double>(specamt, AdbLimit);
+ er_ded += r * std::min(specamt.d(), AdbLimit);
}
// Paid by ee.
@@ -1312,7 +1312,7 @@ std::pair<double,double> BasicValues::approx_mly_ded_ex
if(true) // Written thus for parallelism and to keep 'r' local.
{
double const r = Loads_->specified_amount_load(mce_gen_curr)[year];
- er_ded += r * std::min<double>(specamt, SpecAmtLoadLimit);
+ er_ded += r * std::min(specamt.d(), SpecAmtLoadLimit);
}
// Paid by er.
@@ -1326,7 +1326,7 @@ std::pair<double,double> BasicValues::approx_mly_ded_ex
case oe_waiver_times_specamt:
{
// Paid by er. (In this case, WP excludes term.)
- er_ded += r * std::min<double>(specamt, WpLimit);
+ er_ded += r * std::min(specamt.d(), WpLimit);
}
break;
case oe_waiver_times_deductions:
diff --git a/ledger_invariant_init.cpp b/ledger_invariant_init.cpp
index 103d149..e759f28 100644
--- a/ledger_invariant_init.cpp
+++ b/ledger_invariant_init.cpp
@@ -143,7 +143,7 @@ void LedgerInvariant::Init(BasicValues const* b)
// Scalable scalars.
// SOMEDAY !! Things indexed with '[0]' should probably use inforce year
instead.
- InitBaseSpecAmt = b->DeathBfts_->specamt()[0];
+ InitBaseSpecAmt = (b->DeathBfts_->specamt()[0]).d();
InitTermSpecAmt = TermSpecAmt[0];
ChildRiderAmount = b->yare_input_.ChildRiderAmount;
SpouseRiderAmount = b->yare_input_.SpouseRiderAmount;
@@ -735,7 +735,7 @@ void LedgerInvariant::ReInit(BasicValues const* b)
}
SpecAmt = doubleize(b->DeathBfts_->specamt());
- InitBaseSpecAmt = b->DeathBfts_->specamt()[0];
+ InitBaseSpecAmt = (b->DeathBfts_->specamt()[0]).d();
InitTermSpecAmt = TermSpecAmt[0];
IsMec = false;
diff --git a/ledgervalues.cpp b/ledgervalues.cpp
index be75c42..7139419 100644
--- a/ledgervalues.cpp
+++ b/ledgervalues.cpp
@@ -40,10 +40,10 @@ double IllusVal::run(Input const& input)
AccountValue av(input);
av.SetDebugFilename(filename_);
- double z = av.RunAV();
+ currency z = av.RunAV();
ledger_ = av.ledger_from_av();
- return z;
+ return z.d(); // or just change return type to currency?
}
std::shared_ptr<Ledger const> IllusVal::ledger() const
diff --git a/solve.cpp b/solve.cpp
index df49fcb..08176c8 100644
--- a/solve.cpp
+++ b/solve.cpp
@@ -84,9 +84,9 @@ currency SolveTest()
// IHS !! Start counting only at end of no-lapse period--lmi does that
already.
for(int j = 0; j < ThatSolveTgtYear; ++j)
{
- Negative = std::min<double>
+ Negative = std::min
(Negative
- ,ConstThat->VariantValues().CSVNet[j]
+ ,currency(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.
@@ -133,7 +133,7 @@ currency SolveTest()
break;
case mce_solve_for_target_csv:
{
- y = ThatSolveTargetValue;
+ y = currency(ThatSolveTargetValue);
}
break;
case mce_solve_for_target_naar: // Fall through.
@@ -155,7 +155,7 @@ inline static double SolveSpecAmt(double CandidateValue)
{
// IHS !! Change surrchg when SA changes?
That->SolveSetSpecAmt(currency(CandidateValue), ThatSolveBegYear,
ThatSolveEndYear);
- return only_set_values ? 0.0 : SolveTest();
+ return only_set_values ? 0.0 : SolveTest().d();
}
//============================================================================
@@ -163,7 +163,7 @@ inline static double SolvePrem(double CandidateValue)
//inline static double SolvePrem(currency CandidateValue)
{
That->SolveSetPmts(currency(CandidateValue), ThatSolveBegYear,
ThatSolveEndYear);
- return only_set_values ? 0.0 : SolveTest();
+ return only_set_values ? 0.0 : SolveTest().d();
}
//============================================================================
@@ -171,7 +171,7 @@ inline static double SolveLoan(double CandidateValue)
//inline static double SolveLoan(currency CandidateValue)
{
That->SolveSetLoans(currency(CandidateValue), ThatSolveBegYear,
ThatSolveEndYear);
- return only_set_values ? 0.0 : SolveTest();
+ return only_set_values ? 0.0 : SolveTest().d();
}
//============================================================================
@@ -179,7 +179,7 @@ inline static double SolveWD(double CandidateValue)
//inline static double SolveWD(currency CandidateValue)
{
That->SolveSetWDs(currency(CandidateValue), ThatSolveBegYear,
ThatSolveEndYear);
- return only_set_values ? 0.0 : SolveTest();
+ return only_set_values ? 0.0 : SolveTest().d();
}
//============================================================================
@@ -283,7 +283,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 = DeathBfts_->specamt()[0].d();
Decimals = 2;
SolveFn = SolvePrem;
}
@@ -353,6 +353,6 @@ currency AccountValue::Solve()
only_set_values = !Solving;
currency actual_solution = currency(Solution.first);
- SolveFn(actual_solution);
+ SolveFn(actual_solution.d());
return actual_solution;
}
- [lmi-commits] [lmi] valyuta/002 49f84a1 60/65: Don't convert type with operator=(), (continued)
- [lmi-commits] [lmi] valyuta/002 49f84a1 60/65: Don't convert type with operator=(), Greg Chicares, 2020/09/16
- [lmi-commits] [lmi] valyuta/002 9a9665c 58/65: Record some speed improvements, Greg Chicares, 2020/09/16
- [lmi-commits] [lmi] valyuta/002 ce34d89 04/65: improve, Greg Chicares, 2020/09/16
- [lmi-commits] [lmi] valyuta/002 8331a5c 07/65: avoid catastrophic cancellation, Greg Chicares, 2020/09/16
- [lmi-commits] [lmi] valyuta/002 0856081 20/65: improve currency, Greg Chicares, 2020/09/16
- [lmi-commits] [lmi] valyuta/002 3d03e4a 41/65: fix typo, Greg Chicares, 2020/09/16
- [lmi-commits] [lmi] valyuta/002 a00f68f 52/65: document, Greg Chicares, 2020/09/16
- [lmi-commits] [lmi] valyuta/002 7de1baa 56/65: Note some more instances of the missing unary operator-(), Greg Chicares, 2020/09/16
- [lmi-commits] [lmi] valyuta/002 4d9fed5 15/65: document, Greg Chicares, 2020/09/16
- [lmi-commits] [lmi] valyuta/002 5489e25 40/65: use data_type, Greg Chicares, 2020/09/16
- [lmi-commits] [lmi] valyuta/002 a32e29b 53/65: Avoid implicit conversions, whose (hidden) cost is very high,
Greg Chicares <=
- [lmi-commits] [lmi] valyuta/002 39d842f 57/65: Simplify: catastrophic cancellation less worrisome with integer math, Greg Chicares, 2020/09/16
- [lmi-commits] [lmi] valyuta/002 d124022 64/65: trace solves in self test, Greg Chicares, 2020/09/16
- [lmi-commits] [lmi] valyuta/002 4f46dd5 59/65: Assert a precondition, Greg Chicares, 2020/09/16