[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[lmi-commits] [lmi] master 72f3387 1/2: Adapt to currency class
From: |
Greg Chicares |
Subject: |
[lmi-commits] [lmi] master 72f3387 1/2: Adapt to currency class |
Date: |
Tue, 26 Jan 2021 16:30:36 -0500 (EST) |
branch: master
commit 72f33873a318c702294b32b99365ce97f8533818
Author: Gregory W. Chicares <gchicares@sbcglobal.net>
Commit: Gregory W. Chicares <gchicares@sbcglobal.net>
Adapt to currency class
---
account_value.hpp | 2 +-
accountvalue.cpp | 31 +++++++++----------
ihs_avmly.cpp | 91 +++++++++++++++++++++++++++++++------------------------
3 files changed, 68 insertions(+), 56 deletions(-)
diff --git a/account_value.hpp b/account_value.hpp
index ee5ce9b..e1dce90 100644
--- a/account_value.hpp
+++ b/account_value.hpp
@@ -420,7 +420,7 @@ class LMI_SO AccountValue final
currency SepAcctValueAfterDeduction;
double GenAcctPaymentAllocation;
double SepAcctPaymentAllocation;
- double NAAR; // CURRENCY !! not currency?
+ currency NAAR;
currency CoiCharge;
currency RiderCharges;
currency NetCoiCharge;
diff --git a/accountvalue.cpp b/accountvalue.cpp
index 8f6e599..e7092d4 100644
--- a/accountvalue.cpp
+++ b/accountvalue.cpp
@@ -687,7 +687,7 @@ void AccountValue::TxPmt()
GrossPmts[Month] = pmt;
if(0 == Year && 0 == Month)
{
- double TotalDumpin =
+ currency TotalDumpin =
Outlay_->dumpin()
+ Outlay_->external_1035_amount()
+ Outlay_->internal_1035_amount()
@@ -743,7 +743,8 @@ void AccountValue::TxSetBOMAV()
void AccountValue::TxSetDeathBft()
{
// Total account value is unloaned plus loaned.
- double AV = AVUnloaned + AVRegLn + AVPrfLn;
+ currency AV = AVUnloaned + AVRegLn + AVPrfLn;
+ currency corr = round_death_benefit().c(YearsCorridorFactor * AV);
// Set death benefit reflecting corridor and death benefit option.
switch(YearsDBOpt)
@@ -751,16 +752,13 @@ void AccountValue::TxSetDeathBft()
case mce_option1:
{
// Option 1: specamt, or corridor times AV if greater.
- deathbft = std::max(ActualSpecAmt, YearsCorridorFactor * AV);
+ deathbft = std::max(ActualSpecAmt, corr);
}
break;
case mce_option2:
// Option 2: specamt plus AV, or corridor times AV if greater.
// Negative AV doesn't decrease death benefit.
- deathbft = std::max
- (ActualSpecAmt + std::max(C0, AV)
- ,YearsCorridorFactor * AV
- );
+ deathbft = std::max(ActualSpecAmt + std::max(C0, AV), corr);
break;
case mce_rop: // fall through
case mce_mdb: // fall through
@@ -782,7 +780,7 @@ void AccountValue::TxSetCoiCharge()
TxSetDeathBft();
// Negative AV doesn't increase NAAR.
- NAAR = round_naar()(deathbft * mlyguarv - (AVUnloaned + AVRegLn +
AVPrfLn));
+ NAAR = round_naar().c(deathbft * mlyguarv - dblize(AVUnloaned + AVRegLn +
AVPrfLn));
CoiCharge = round_coi_charge().c(NAAR * YearsCoiRate0);
}
@@ -806,7 +804,7 @@ void AccountValue::TxSetRiderDed()
AdbCharge = round_rider_charges().c
( YearsAdbRate
// IHS !! Icky manifest constant--lmi uses a database entity.
- * std::min(500000.0, ActualSpecAmt)
+ * std::min(from_cents(50000000), ActualSpecAmt)
);
}
}
@@ -895,7 +893,7 @@ void AccountValue::TxTakeWD()
// max loan: cannot become overloaned until end of policy year.
// However, lmi provides a variety of implementations instead of
// only one.
- double max_wd =
+ currency max_wd =
AVUnloaned
+ (AVRegLn + AVPrfLn)
- (RegLnBal + PrfLnBal)
@@ -971,20 +969,21 @@ void AccountValue::TxTakeLoan()
// Impose maximum amount.
// If maximum exceeded...limit it.
// IHS !! For solves, the lmi branch uses an 'ullage' concept.
- MaxLoan =
+ double max_loan =
AVUnloaned * 0.9 // IHS !! Icky manifest constant--lmi uses a
database entity.
// - surrchg
- + (AVRegLn + AVPrfLn)
+ + dblize(AVRegLn + AVPrfLn)
- RegLnBal * (std::pow((1.0 + YearsRegLnIntDueRate), 12 - Month) - 1.0)
- PrfLnBal * (std::pow((1.0 + YearsPrfLnIntDueRate), 12 - Month) - 1.0)
- - mlydedtonextmodalpmtdate;
+ - dblize(mlydedtonextmodalpmtdate)
+ ;
// 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);
IntAdj = (IntAdj - 1.0) / IntAdj;
- MaxLoan *= 1.0 - IntAdj;
- MaxLoan = std::max(0.0, MaxLoan);
- MaxLoan = round_loan()(MaxLoan);
+ max_loan *= 1.0 - IntAdj;
+ max_loan = std::max(0.0, max_loan);
+ MaxLoan = round_loan().c(max_loan);
// IHS !! Preferred loan calculations would go here: implemented in lmi.
diff --git a/ihs_avmly.cpp b/ihs_avmly.cpp
index 318eaba..d448201 100644
--- a/ihs_avmly.cpp
+++ b/ihs_avmly.cpp
@@ -990,8 +990,8 @@ void AccountValue::TxSpecAmtChange()
ChangeSupplAmtBy(DeathBfts_->supplamt()[Year] - TermSpecAmt);
}
- double const new_specamt = DeathBfts_->specamt()[Year];
- double const old_specamt = DeathBfts_->specamt()[Year - 1];
+ currency const new_specamt = DeathBfts_->specamt()[Year];
+ currency const old_specamt = DeathBfts_->specamt()[Year - 1];
// Nothing to do if no increase or decrease requested.
// TODO ?? new_specamt != ActualSpecAmt; the latter should be used.
@@ -1342,8 +1342,8 @@ void AccountValue::TxAcceptPayment(currency a_pmt)
LMI_ASSERT(C0 <= a_pmt);
// Internal 1035 exchanges may be exempt from premium tax; they're
// handled elsewhere, so here the exempt amount is always zero.
- double actual_load = GetPremLoad(a_pmt, C0);
- double net_pmt = a_pmt - actual_load;
+ currency actual_load = GetPremLoad(a_pmt, C0);
+ currency net_pmt = a_pmt - actual_load;
LMI_ASSERT(C0 <= net_pmt);
NetPmts[Month] += net_pmt;
@@ -1399,7 +1399,7 @@ currency AccountValue::GetPremLoad
,currency a_portion_exempt_from_premium_tax
)
{
- double excess_portion;
+ currency excess_portion;
// All excess.
if(C0 == UnusedTargetPrem)
{
@@ -1417,7 +1417,7 @@ currency AccountValue::GetPremLoad
excess_portion = C0;
UnusedTargetPrem -= a_pmt;
}
- double target_portion = a_pmt - excess_portion;
+ currency target_portion = a_pmt - excess_portion;
premium_load_ =
target_portion * YearsPremLoadTgt
@@ -1432,7 +1432,7 @@ currency AccountValue::GetPremLoad
CumulativeSalesLoad += round_net_premium().c(sales_load_);
premium_tax_load_ = PremiumTax_->calculate_load
- (a_pmt - a_portion_exempt_from_premium_tax
+ (dblize(a_pmt - a_portion_exempt_from_premium_tax)
,*StratifiedCharges_
);
@@ -1491,7 +1491,8 @@ void AccountValue::TxLoanRepay()
return;
}
- // TODO ?? This idiom seems too cute. And it can return -0.0 .
+ // TODO ?? This idiom seems too cute. And it can return -0.0 . See:
+ // https://lists.nongnu.org/archive/html/lmi/2020-09/msg00005.html
// Maximum repayment is total debt.
ActualLoan = -std::min(-RequestedLoan, RegLnBal + PrfLnBal);
@@ -1575,8 +1576,8 @@ void AccountValue::TxSetBOMAV()
///
/// TODO ?? TAXATION !! Should 7702 or 7702A processing be done here?
/// If so, then this code may be useful:
-/// double prior_db_7702A = DB7702A;
-/// double prior_sa_7702A = ActualSpecAmt;
+/// currency prior_db_7702A = DB7702A;
+/// currency prior_sa_7702A = ActualSpecAmt;
/// toward the beginning, and:
/// Irc7702A_->UpdateBft7702A(...);
/// LMI_ASSERT(0.0 <= Dcv);
@@ -1622,7 +1623,7 @@ void AccountValue::TxSetDeathBft()
// Surrender charges are generally ignored here, but any negative
// surrender charge must be subtracted, increasing the account value.
- double cash_value_for_corridor =
+ currency cash_value_for_corridor =
TotalAccountValue()
- std::min(C0, SurrChg())
+ GetRefundableSalesLoad()
@@ -1685,7 +1686,7 @@ void AccountValue::TxSetTermAmt()
}
TermDB = std::max(C0, TermSpecAmt + DBIgnoringCorr - DBReflectingCorr);
- TermDB = round_death_benefit()(TermDB);
+ TermDB = round_death_benefit().c(TermDB);
}
/// Terminate the term rider, optionally converting it to base.
@@ -1716,7 +1717,7 @@ void AccountValue::EndTermRider(bool convert)
ChangeSpecAmtBy(TermSpecAmt);
}
TermSpecAmt = C0;
- TermDB = C0;
+ TermDB = C0;
// Carry the new term spec amt forward into all future years.
for(int j = Year; j < BasicValues::GetLength(); ++j)
{
@@ -1738,19 +1739,27 @@ void AccountValue::TxSetCoiCharge()
// than zero because the corridor factor can be as low as unity,
// but it's constrained to be nonnegative to prevent increasing
// the account value by deducting a negative mortality charge.
+#if defined USE_CURRENCY_CLASS
+ NAAR = round_naar().c
+ ( DBReflectingCorr * DBDiscountRate[Year]
+ - dblize(std::max(C0, TotalAccountValue()))
+ );
+ LMI_ASSERT(C0 <= NAAR);
+#else // !defined USE_CURRENCY_CLASS
NAAR = material_difference
(DBReflectingCorr * DBDiscountRate[Year]
,std::max(0.0, TotalAccountValue())
);
NAAR = std::max(0.0, round_naar()(NAAR));
+#endif // !defined USE_CURRENCY_CLASS
// TODO ?? This doesn't work. We need to reconsider the basic transactions.
-// double naar_forceout = std::max(0.0, NAAR - MaxNAAR);
+// currency naar_forceout = std::max(0.0, NAAR - MaxNAAR);
// process_distribution(naar_forceout);
// TAXATION !! Should this be handled at the same time as GPT forceouts?
DcvNaar = material_difference
- (std::max(DcvDeathBft, DBIgnoringCorr) * DBDiscountRate[Year]
+ (std::max(DcvDeathBft, dblize(DBIgnoringCorr)) * DBDiscountRate[Year]
,std::max(0.0, Dcv)
);
// DCV need not be rounded.
@@ -1780,11 +1789,11 @@ void AccountValue::TxSetCoiCharge()
)
);
double retention_rate = round_coi_rate()(coi_rate * CoiRetentionRate);
- retention_charge = round_coi_charge()(NAAR * retention_rate);
+ retention_charge = NAAR * retention_rate;
}
CoiCharge = round_coi_charge().c(NAAR * ActualCoiRate);
- NetCoiCharge = CoiCharge - retention_charge;
+ NetCoiCharge = CoiCharge - round_coi_charge().c(retention_charge);
YearsTotalCoiCharge += CoiCharge;
// DCV need not be rounded.
@@ -1799,7 +1808,7 @@ void AccountValue::TxSetRiderDed()
if(yare_input_.AccidentalDeathBenefit)
{
AdbCharge = round_rider_charges().c
- (YearsAdbRate * std::min(ActualSpecAmt, AdbLimit)
+ (YearsAdbRate * std::min(dblize(ActualSpecAmt), AdbLimit)
);
}
@@ -1842,7 +1851,7 @@ void AccountValue::TxSetRiderDed()
case oe_waiver_times_specamt:
{
WpCharge = round_rider_charges().c
- (YearsWpRate * std::min(ActualSpecAmt, WpLimit)
+ (YearsWpRate * std::min(dblize(ActualSpecAmt), WpLimit)
);
DcvWpCharge = WpCharge;
}
@@ -1892,7 +1901,7 @@ void AccountValue::TxDoMlyDed()
}
// 'Simple' riders are the same for AV and DCV.
- double simple_rider_charges =
+ currency simple_rider_charges =
AdbCharge
+ SpouseRiderCharge
+ ChildRiderCharge
@@ -1921,7 +1930,7 @@ void AccountValue::TxDoMlyDed()
// determined.
MlyDed += MonthsPolicyFees + SpecAmtLoad;
- YearsTotalNetCoiCharge += NetCoiCharge;
+ YearsTotalNetCoiCharge += dblize(NetCoiCharge);
SepAcctValueAfterDeduction = AVSepAcct;
}
@@ -1945,7 +1954,7 @@ void AccountValue::TxTestHoneymoonForExpiration()
// experience rating reserve would affect the cash surrender value
// but not the honeymoon value.
//
- double csv_ignoring_loan =
+ currency csv_ignoring_loan =
TotalAccountValue()
- SurrChg()
+ GetRefundableSalesLoad()
@@ -1963,7 +1972,11 @@ void AccountValue::TxTestHoneymoonForExpiration()
if(HoneymoonValue <= C0 || HoneymoonValue < csv_ignoring_loan)
{
HoneymoonActive = false;
- HoneymoonValue = -std::numeric_limits<double>::max();
+#if defined USE_CURRENCY_CLASS
+ HoneymoonValue =
-from_cents(std::numeric_limits<currency::data_type>::max());
+#else // !defined USE_CURRENCY_CLASS
+ HoneymoonValue = -std::numeric_limits<double>::max();
+#endif // !defined USE_CURRENCY_CLASS
}
}
@@ -2118,7 +2131,7 @@ void AccountValue::TxCreditInt()
{
ApplyDynamicMandE(AssetsPostBom);
- double notional_sep_acct_charge = C0;
+ currency notional_sep_acct_charge = C0;
// SOMEDAY !! This should be done in the interest-rate class.
double gross_sep_acct_rate = i_upper_12_over_12_from_i<double>()
@@ -2130,10 +2143,10 @@ void AccountValue::TxCreditInt()
gross_sep_acct_rate = 0.0;
}
- if(0.0 < AVSepAcct)
+ if(C0 < AVSepAcct)
{
SepAcctIntCred = InterestCredited(AVSepAcct, YearsSepAcctIntRate);
- double gross = InterestCredited(AVSepAcct, gross_sep_acct_rate);
+ currency gross = InterestCredited(AVSepAcct, gross_sep_acct_rate);
notional_sep_acct_charge = gross - SepAcctIntCred;
// Guard against catastrophic cancellation. Testing the
// absolute values of the addends for material equality is not
@@ -2154,7 +2167,7 @@ void AccountValue::TxCreditInt()
SepAcctIntCred = C0;
}
- if(0.0 < AVGenAcct)
+ if(C0 < AVGenAcct)
{
double effective_general_account_interest_factor = YearsGenAcctIntRate;
if
@@ -2195,7 +2208,7 @@ void AccountValue::TxCreditInt()
// Loaned account value must not be negative.
LMI_ASSERT(C0 <= AVRegLn && C0 <= AVPrfLn);
- double z = RegLnIntCred + PrfLnIntCred + SepAcctIntCred + GenAcctIntCred;
+ currency z = RegLnIntCred + PrfLnIntCred + SepAcctIntCred + GenAcctIntCred;
YearsTotalNetIntCredited += z;
YearsTotalGrossIntCredited += z + notional_sep_acct_charge;
}
@@ -2223,8 +2236,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;
@@ -2257,11 +2270,11 @@ currency AccountValue::anticipated_deduction
{
case mce_twelve_times_last:
{
- return 12.0 * MlyDed;
+ return 12 * MlyDed;
}
case mce_eighteen_times_last:
{
- return 18.0 * MlyDed;
+ return 18 * MlyDed;
}
case mce_to_next_anniversary:
{
@@ -2348,7 +2361,7 @@ void AccountValue::TxTakeWD()
if(Solving || mce_run_gen_curr_sep_full == RunBasis_)
{
- NetWD = round_withdrawal()(std::min(RequestedWD, MaxWD));
+ NetWD = round_withdrawal().c(std::min(RequestedWD, MaxWD));
OverridingWD[Year] = NetWD;
}
else
@@ -2459,8 +2472,8 @@ void AccountValue::TxTakeWD()
// the fee based on the requested proceeds and add that
// to the partial surrender amount.
- double av = TotalAccountValue();
- double csv = av - SurrChg_[Year];
+ currency av = TotalAccountValue();
+ currency csv = av - SurrChg_[Year];
LMI_ASSERT(C0 <= SurrChg_[Year]);
if(csv <= C0)
{
@@ -2482,7 +2495,7 @@ void AccountValue::TxTakeWD()
// distinct surrender-charge layers.
double surrchg_proportion = SurrChg_[Year] / csv;
- double non_free_wd = GrossWD;
+ currency non_free_wd = GrossWD;
if(0.0 != FreeWDProportion[Year])
{
// The free partial surrender amount is determined annually,
@@ -2491,11 +2504,11 @@ void AccountValue::TxTakeWD()
LMI_ASSERT(AVRegLn == RegLnBal);
LMI_ASSERT(AVPrfLn == PrfLnBal);
LMI_ASSERT(av == AVGenAcct + AVSepAcct);
- double free_wd = FreeWDProportion[Year] * av;
+ currency free_wd = round_withdrawal().c(FreeWDProportion[Year] * av);
non_free_wd = std::max(C0, GrossWD - free_wd);
}
double partial_surrchg = non_free_wd * surrchg_proportion;
- GrossWD += round_withdrawal()(partial_surrchg);
+ GrossWD += round_withdrawal().c(partial_surrchg);
process_distribution(GrossWD);
Dcv -= GrossWD;
@@ -2763,7 +2776,7 @@ void AccountValue::TxTestLapse()
// is an actual balance-sheet item that is actually held in the
// certificate.
- double lapse_test_csv =
+ currency lapse_test_csv =
TotalAccountValue()
- (RegLnBal + PrfLnBal)
// + std::max(0.0, ExpRatReserve) // This would be added if it existed.