[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[lmi-commits] [lmi] valyuta/005 d5c50ee 1/5: Resolve more gratuitous inc
From: |
Greg Chicares |
Subject: |
[lmi-commits] [lmi] valyuta/005 d5c50ee 1/5: Resolve more gratuitous incompatibilities with master |
Date: |
Thu, 28 Jan 2021 17:53:33 -0500 (EST) |
branch: valyuta/005
commit d5c50ee53a0cbf27cbc4099cc4c662cf2a7a8eea
Author: Gregory W. Chicares <gchicares@sbcglobal.net>
Commit: Gregory W. Chicares <gchicares@sbcglobal.net>
Resolve more gratuitous incompatibilities with master
---
accountvalue.cpp | 35 +++++----
basicvalues.cpp | 11 +--
ihs_acctval.cpp | 55 ++++-----------
ihs_avmly.cpp | 211 ++++++++++++++++++++++++-------------------------------
ihs_avsolve.cpp | 19 ++---
ihs_basicval.cpp | 26 +++----
solve.cpp | 10 +--
7 files changed, 149 insertions(+), 218 deletions(-)
diff --git a/accountvalue.cpp b/accountvalue.cpp
index 4ee32d4..7787cc6 100644
--- a/accountvalue.cpp
+++ b/accountvalue.cpp
@@ -486,8 +486,6 @@ void AccountValue::PerformSpecAmtStrategy()
}
}
- SA = round_specamt().c(SA); // already rounded
-
for(int j = 0; j < BasicValues::GetLength(); ++j)
{
InvariantValues().SpecAmt[j] = dblize(SA);
@@ -545,7 +543,8 @@ void AccountValue::TxOptionChange()
alarum() << "Case " << YearsDBOpt << " not found." << LMI_FLUSH;
}
}
- ActualSpecAmt = round_specamt().c(ActualSpecAmt); // already rounded
+ // AV normally rounded to cents, but specamt perhaps to dollars.
+ ActualSpecAmt = round_specamt().c(ActualSpecAmt);
// Carry the new spec amt forward into all future years.
for(int j = Year; j < BasicValues::GetLength(); ++j)
@@ -758,10 +757,7 @@ void AccountValue::TxSetDeathBft()
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)
- ,corr
- );
+ deathbft = std::max(ActualSpecAmt + std::max(C0, AV), corr);
break;
case mce_rop: // fall through
case mce_mdb: // fall through
@@ -771,7 +767,7 @@ void AccountValue::TxSetDeathBft()
}
}
- deathbft = round_death_benefit().c(deathbft); // already rounded
+ deathbft = round_death_benefit().c(deathbft);
// SOMEDAY !! Accumulate average death benefit for profit testing here.
}
@@ -783,8 +779,7 @@ void AccountValue::TxSetCoiCharge()
TxSetDeathBft();
// Negative AV doesn't increase NAAR.
- NAAR = deathbft * mlyguarv - dblize(AVUnloaned + AVRegLn + AVPrfLn);
- NAAR = round_naar()(NAAR);
+ NAAR = round_naar()(deathbft * mlyguarv - dblize(AVUnloaned + AVRegLn +
AVPrfLn));
CoiCharge = round_coi_charge().c(NAAR * YearsCoiRate0);
}
@@ -797,8 +792,7 @@ void AccountValue::TxSetRiderDed()
if(haswp)
{
WpCharge = round_rider_charges().c
- (
- YearsWpRate
+ ( YearsWpRate
* (CoiCharge + YearsMonthlyPolicyFee + AdbCharge)
);
}
@@ -806,7 +800,11 @@ void AccountValue::TxSetRiderDed()
AdbCharge = C0;
if(hasadb)
{
- AdbCharge = round_rider_charges().c(YearsAdbRate * std::min(500000.0,
dblize(ActualSpecAmt)));
+ AdbCharge = round_rider_charges().c
+ ( YearsAdbRate
+ // IHS !! Icky manifest constant--lmi uses a database entity.
+ * std::min(from_cents(50000000), ActualSpecAmt)
+ );
}
}
@@ -828,8 +826,7 @@ void AccountValue::TxCreditInt()
if(C0 < AVUnloaned)
{
// IHS !! Each interest increment is rounded separately in lmi.
- currency z = round_interest_credit().c(AVUnloaned *
YearsGenAcctIntRate);
- AVUnloaned += z;
+ AVUnloaned += round_interest_credit().c(AVUnloaned *
YearsGenAcctIntRate);
}
// Loaned account value cannot be negative.
LMI_ASSERT(C0 <= AVRegLn + AVPrfLn);
@@ -920,7 +917,7 @@ void AccountValue::TxTakeWD()
// IHS !! ActualSpecAmt = std::min(ActualSpecAmt, deathbft - wd);
ActualSpecAmt -= wd;
ActualSpecAmt = std::max(ActualSpecAmt, MinSpecAmt);
- ActualSpecAmt = round_specamt().c(ActualSpecAmt); // already
rounded
+ ActualSpecAmt = round_specamt().c(ActualSpecAmt);
// IHS !! If WD causes AV < min AV, do we:
// reduce the WD?
// lapse the policy?
@@ -972,11 +969,11 @@ void AccountValue::TxTakeLoan()
// If maximum exceeded...limit it.
// IHS !! For solves, the lmi branch uses an 'ullage' concept.
double max_loan =
- dblize(AVUnloaned) * 0.9 // IHS !! Icky manifest constant--lmi
uses a database entity.
+ AVUnloaned * 0.9 // IHS !! Icky manifest constant--lmi uses a
database entity.
// - surrchg
+ dblize(AVRegLn + AVPrfLn)
- - dblize(RegLnBal) * (std::pow((1.0 + YearsRegLnIntDueRate), 12 -
Month) - 1.0)
- - dblize(PrfLnBal) * (std::pow((1.0 + YearsPrfLnIntDueRate), 12 -
Month) - 1.0)
+ - RegLnBal * (std::pow((1.0 + YearsRegLnIntDueRate), 12 - Month) - 1.0)
+ - PrfLnBal * (std::pow((1.0 + YearsPrfLnIntDueRate), 12 - Month) - 1.0)
- dblize(mlydedtonextmodalpmtdate)
;
// Interest adjustment: d upper n where n is # months remaining in year.
diff --git a/basicvalues.cpp b/basicvalues.cpp
index 05eee6e..08a2d1b 100644
--- a/basicvalues.cpp
+++ b/basicvalues.cpp
@@ -119,14 +119,9 @@ void BasicValues::Init()
PremiumTax_ .reset(new premium_tax (PremiumTaxState_, database()));
Loads_ .reset(new Loads(database(), IsSubjectToIllustrationReg()));
-// database().query_into(DB_MinSpecAmt, MinSpecAmt);
-// database().query_into(DB_MinWd , MinWD );
-// database().query_into(DB_WdFee , WDFee );
-// database().query_into(DB_WdFeeRate , WDFeeRate );
- MinSpecAmt = round_specamt ().c(database().query<int>(DB_MinSpecAmt));
- MinWD = round_withdrawal().c(database().query<int>(DB_MinWd ));
- WDFee = round_withdrawal().c(database().query<int>(DB_WdFee ));
-// WDFeeRate = database().query<int>(DB_WdFeeRate ); // no, this line looks
wrong
+ MinSpecAmt = round_specamt ().c(database().query<double>(DB_MinSpecAmt));
+ MinWD = round_withdrawal().c(database().query<double>(DB_MinWd ));
+ WDFee = round_withdrawal().c(database().query<double>(DB_WdFee ));
database().query_into(DB_WdFeeRate , WDFeeRate );
// The antediluvian branch leaves FundData_, StratifiedCharges_, and
diff --git a/ihs_acctval.cpp b/ihs_acctval.cpp
index ac3aa29..bc747de 100644
--- a/ihs_acctval.cpp
+++ b/ihs_acctval.cpp
@@ -256,8 +256,6 @@ void AccountValue::SetGuarPrem()
{
GuarPremium = SolveGuarPremium();
}
- // bignum: the largest integer convertible to and from double.
- LMI_ASSERT(GuarPremium < from_cents(1LL << 53));
ledger_->SetGuarPremium(dblize(GuarPremium));
}
@@ -428,20 +426,20 @@ void AccountValue::InitializeLife(mcenum_run_basis
a_Basis)
SurrChg_.assign(BasicValues::GetLength(), C0);
// TAXATION !! Input::InforceAnnualTargetPremium should be used here.
- double annual_target_premium = dblize(GetModalTgtPrem
+ currency annual_target_premium = GetModalTgtPrem
(0
,mce_annual
,base_specamt(0)
- ));
- double sa = dblize(specamt_for_7702(0));
+ );
+ currency sa = specamt_for_7702(0);
// It is at best superfluous to do this for every basis.
// TAXATION !! Don't do that then.
Irc7702_->Initialize7702
- (sa
- ,sa
+ (dblize(sa)
+ ,dblize(sa)
,effective_dbopt_7702(DeathBfts_->dbopt()[0], Effective7702DboRop)
- ,annual_target_premium
+ ,dblize(annual_target_premium)
);
InvariantValues().InitGLP = Irc7702_->RoundedGLP();
@@ -647,16 +645,13 @@ void AccountValue::SetInitialValues()
DcvWpCharge = 0.0;
HoneymoonActive = false;
- // In 'master', this is
- // -std::numeric_limits<double>::max()
- // which is the identity element for std::max(). Here, it's nearly
- // the equivalent for currency::data_type; dividing it by 101 is a
- // casual defense against commuting between dollars and cents.
+ // Identity element for std::max(), disregarding -INF and NaN.
+ // CURRENCY !! support infinities?
#if defined USE_CURRENCY_CLASS
- HoneymoonValue =
from_cents(-std::numeric_limits<currency::data_type>::max() / 101);
+ 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
+#endif // !defined USE_CURRENCY_CLASS
if(mce_gen_curr == GenBasis_)
{
HoneymoonActive = yare_input_.HoneymoonEndorsement;
@@ -989,7 +984,7 @@ void AccountValue::set_list_bill_premium()
);
InvariantValues().EeListBillPremium = dblize(z.first);
InvariantValues().ErListBillPremium = dblize(z.second);
- InvariantValues().ListBillPremium = dblize(z.first) + dblize(z.second);
+ InvariantValues().ListBillPremium = dblize(z.first + z.second);
}
}
@@ -1027,7 +1022,7 @@ void AccountValue::set_modal_min_premium()
);
InvariantValues().EeModalMinimumPremium[Year] = dblize(z.first);
InvariantValues().ErModalMinimumPremium[Year] = dblize(z.second);
- InvariantValues().ModalMinimumPremium[Year] = dblize(z.first) +
dblize(z.second);
+ InvariantValues().ModalMinimumPremium[Year] = dblize(z.first +
z.second);
}
}
@@ -1105,17 +1100,6 @@ void AccountValue::SetClaims()
YearsGrossClaims = partial_mortality_qx()[Year] * DBReflectingCorr;
YearsAVRelOnDeath = partial_mortality_qx()[Year] *
TotalAccountValue();
YearsLoanRepaidOnDeath = partial_mortality_qx()[Year] * (RegLnBal +
PrfLnBal);
-#if 0
- // presumably material_difference() isn't needed at all
- YearsDeathProceeds = material_difference
- (YearsGrossClaims
- ,YearsLoanRepaidOnDeath
- );
- YearsNetClaims = material_difference
- (YearsGrossClaims
- ,YearsAVRelOnDeath
- );
-#endif // 0
YearsDeathProceeds = material_difference
(YearsGrossClaims
,YearsLoanRepaidOnDeath
@@ -1153,9 +1137,9 @@ void AccountValue::SetProjectedCoiCharge()
TxSetDeathBft();
TxSetTermAmt();
- // presumably material_difference() isn't needed at all? um...yes, it is
+ // CURRENCY !! presumably material_difference() isn't needed at all?
um...yes, it is
double this_years_terminal_naar = material_difference
- (dblize((DBReflectingCorr + TermDB))
+ (dblize(DBReflectingCorr + TermDB)
,dblize(TotalAccountValue())
);
this_years_terminal_naar = std::max(0.0, this_years_terminal_naar);
@@ -1310,15 +1294,6 @@ void AccountValue::FinalizeYear()
+ YearsTotalGrossIntCredited
- YearsTotalNetIntCredited
;
-#if 0 // not needed--already currency
- double notional_sep_acct_charge =
- dblize(YearsTotalSepAcctLoad)
- + material_difference
- (YearsTotalGrossIntCredited
- ,YearsTotalNetIntCredited
- )
- ;
-#endif // 0
VariantValues().SepAcctCharges [Year] =
dblize(notional_sep_acct_charge);
// Record dynamic interest rate in ledger object.
@@ -1383,7 +1358,6 @@ void AccountValue::FinalizeYear()
{
InvariantValues().InitPrem = InvariantValues().GrossPmt[Year];
}
-#if 1
LMI_ASSERT
(materially_equal
( InvariantValues().GrossPmt [Year]
@@ -1391,7 +1365,6 @@ void AccountValue::FinalizeYear()
+ InvariantValues().ErGrossPmt[Year]
)
);
-#endif // 0
InvariantValues().Outlay[Year] =
InvariantValues().GrossPmt [Year]
- InvariantValues().NetWD [Year]
diff --git a/ihs_avmly.cpp b/ihs_avmly.cpp
index a0f88a9..70444f7 100644
--- a/ihs_avmly.cpp
+++ b/ihs_avmly.cpp
@@ -151,7 +151,6 @@ void AccountValue::DoMonthDR()
// + std::max(0.0, ExpRatReserve) // This would be added if it
existed.
);
// TODO ?? TAXATION !! Use CashValueFor7702() instead?
- // Not already rounded by class Irc7702A.
double max_necessary_premium = Irc7702A_->MaxNecessaryPremium
(Dcv
,dblize(AnnualTargetPrem)
@@ -161,7 +160,7 @@ void AccountValue::DoMonthDR()
);
// TAXATION !! Should round here, but need to investigate regressions.
// max_necessary_premium = round_max_premium()(max_necessary_premium);
- // Already rounded by class Irc7702A.
+ // CURRENCY !! already rounded by class Irc7702A--appropriately?
double max_non_mec_premium = Irc7702A_->MaxNonMecPremium
(Dcv
,dblize(AnnualTargetPrem)
@@ -191,7 +190,7 @@ void AccountValue::DoMonthDR()
{
Irc7702A_->UpdatePmt7702A
(Dcv
- ,-dblize(NetWD) // TAXATION !! This should be gross, not net.
+ ,dblize(-NetWD) // TAXATION !! This should be gross, not net.
,false
,dblize(AnnualTargetPrem)
,YearsTotLoadTgtLowestPremtax
@@ -205,34 +204,22 @@ void AccountValue::DoMonthDR()
{
gross_1035 = External1035Amount + Internal1035Amount;
}
- double necessary_premium = std::min // round?
- (material_difference // round?
+ // CURRENCY !! currency is immune to catastrophic cancellation
+ double necessary_premium = std::min
+ // CURRENCY !! Wouldn't simple subtraction do, for currency?
+ (material_difference
(dblize(GrossPmts[Month])
,dblize(gross_1035)
)
,max_necessary_premium
);
- double unnecessary_premium = material_difference // round?
+ // CURRENCY !! Wouldn't simple subtraction do, for currency?
+ double unnecessary_premium = material_difference
(dblize(GrossPmts[Month])
,dblize(gross_1035) + necessary_premium
);
-// NetMaxNecessaryPremium
-// GrossMaxNecessaryPremium
NecessaryPremium = round_minutiae().c(necessary_premium );
UnnecessaryPremium = round_minutiae().c(unnecessary_premium);
- if(necessary_premium < 0.0 || unnecessary_premium < 0.0)
- warning()
-// << GrossPmts[Month] << " GrossPmts[Month]\n"
-// << gross_1035 << " gross_1035\n"
-// << GrossPmts[Month] - gross_1035 << " GrossPmts[Month] -
gross_1035\n"
- << necessary_premium << " necessary_premium\n"
- << unnecessary_premium << " unnecessary_premium\n"
- << Year << " Year\n"
- << Month << " Month\n"
-// << z << " z\n"
- << LMI_FLUSH
- ;
-
// It is crucial to accept necessary premium before processing a
// material change, so that the correct DCV is used.
TxRecognizePaymentFor7702A(NecessaryPremium, false);
@@ -255,7 +242,6 @@ void AccountValue::DoMonthDR()
);
LMI_ASSERT(0.0 <= Dcv);
-// UnnecessaryPremium = unnecessary_premium; // moved up
TxRecognizePaymentFor7702A(UnnecessaryPremium, true);
TxAcceptPayment(UnnecessaryPremium);
@@ -305,6 +291,7 @@ void AccountValue::process_payment(currency payment)
double er_proportion = 0.0;
if(C0 != gross_non_1035_pmts)
{
+ // CURRENCY !! more efficient: currency / currency --> double
er_proportion = ErGrossPmts[Month] / dblize(gross_non_1035_pmts);
}
@@ -356,7 +343,7 @@ void AccountValue::process_payment(currency payment)
// portions of unloaned account value according to input allocations.
void AccountValue::IncrementAVProportionally(currency increment)
{
- increment = round_minutiae().c(increment); // already rounded?
+ increment = round_minutiae().c(increment); // CURRENCY !! already rounded?
currency genacct_increment = round_minutiae().c(increment *
GenAcctPaymentAllocation);
AVGenAcct += genacct_increment;
AVSepAcct += increment - genacct_increment;
@@ -441,10 +428,13 @@ void AccountValue::process_distribution(currency
decrement)
void AccountValue::DecrementAVProportionally(currency decrement)
{
- decrement = round_minutiae().c(decrement); // already rounded?
+ decrement = round_minutiae().c(decrement); // CURRENCY !! already rounded?
-// if(materially_equal(decrement, AVGenAcct + AVSepAcct))
+#if defined USE_CURRENCY_CLASS
if(decrement == AVGenAcct + AVSepAcct)
+#else // !defined USE_CURRENCY_CLASS
+ if(materially_equal(decrement, AVGenAcct + AVSepAcct))
+#endif // !defined USE_CURRENCY_CLASS
{
AVGenAcct = C0;
AVSepAcct = C0;
@@ -453,8 +443,9 @@ void AccountValue::DecrementAVProportionally(currency
decrement)
double general_account_proportion = 0.0;
double separate_account_proportion = 0.0;
- double general_account_nonnegative_assets = std::max(0.0,
dblize(AVGenAcct));
- double separate_account_nonnegative_assets = std::max(0.0,
dblize(AVSepAcct));
+ // CURRENCY !! more efficient: currency / currency --> double
+ double general_account_nonnegative_assets = dblize(std::max(C0,
AVGenAcct));
+ double separate_account_nonnegative_assets = dblize(std::max(C0,
AVSepAcct));
if
( 0.0 == general_account_nonnegative_assets
&& 0.0 == separate_account_nonnegative_assets
@@ -511,8 +502,11 @@ void AccountValue::DecrementAVProgressively
,oenum_increment_account_preference preferred_account
)
{
-// if(materially_equal(decrement, AVGenAcct + AVSepAcct))
+#if defined USE_CURRENCY_CLASS
if(decrement == AVGenAcct + AVSepAcct)
+#else // !defined USE_CURRENCY_CLASS
+ if(materially_equal(decrement, AVGenAcct + AVSepAcct))
+#endif // !defined USE_CURRENCY_CLASS
{
AVGenAcct = C0;
AVSepAcct = C0;
@@ -567,7 +561,7 @@ void AccountValue::TxExch1035()
// Illustration-reg guaranteed premium ignores GPT limit.
if(!SolvingForGuarPremium)
{
- // Maybe this should return the modified value instead of altering
the argument.
+ // CURRENCY !! return modified value instead of altering argument
double z = dblize(GrossPmts[Month]);
Irc7702_->ProcessGptPmt(Year, z);
GrossPmts[Month] = round_gross_premium().c(z);
@@ -627,8 +621,7 @@ void AccountValue::TxExch1035()
CumPmts += GrossPmts[Month];
TaxBasis += round_minutiae().c
- (
- yare_input_.External1035ExchangeTaxBasis
+ ( yare_input_.External1035ExchangeTaxBasis
+ yare_input_.Internal1035ExchangeTaxBasis
);
@@ -731,7 +724,7 @@ currency AccountValue::minimum_specified_amount(bool
issuing_now, bool term_ride
// Make sure ActualSpecAmt is never less than minimum specamt.
void AccountValue::ChangeSpecAmtBy(currency delta)
{
- delta = round_specamt().c(delta); // already rounded?
+ delta = round_specamt().c(delta); // CURRENCY !! already rounded?
double term_proportion = 0.0;
currency const old_total_specamt = ActualSpecAmt + TermSpecAmt;
// Adjust term here only if it's formally a rider.
@@ -746,6 +739,7 @@ void AccountValue::ChangeSpecAmtBy(currency delta)
break;
case mce_adjust_both:
{
+ // CURRENCY !! more efficient: currency / currency --> double
term_proportion = TermSpecAmt / dblize(old_total_specamt);
}
break;
@@ -789,11 +783,9 @@ void AccountValue::ChangeSpecAmtBy(currency delta)
// If specamt would be reduced below the minimum (e.g., by a large
// withdrawal), then force it to the minimum.
- ActualSpecAmt =
- (std::max
- (ActualSpecAmt
- ,minimum_specified_amount(0 == Year && 0 == Month, TermRiderActive)
- )
+ ActualSpecAmt = std::max
+ (ActualSpecAmt
+ ,minimum_specified_amount(0 == Year && 0 == Month, TermRiderActive)
);
// Carry the new specamt forward into all future years.
@@ -824,16 +816,14 @@ void AccountValue::ChangeSpecAmtBy(currency delta)
void AccountValue::ChangeSupplAmtBy(currency delta)
{
- delta = round_specamt().c(delta); // already rounded?
+ delta = round_specamt().c(delta); // CURRENCY !! already rounded?
TermSpecAmt += delta;
- TermSpecAmt = std::max
- (TermSpecAmt
- ,C0 // No minimum other than zero is defined.
- );
- // At least for now, there is no effect on surrender charges.
+ // No minimum other than zero is defined.
+ TermSpecAmt = std::max(TermSpecAmt, C0);
// Carry the new supplemental amount forward into all future years.
+ // At least for now, there is no effect on surrender charges.
for(int j = Year; j < BasicValues::GetLength(); ++j)
{
InvariantValues().TermSpecAmt[j] = dblize(TermSpecAmt);
@@ -1008,7 +998,7 @@ void AccountValue::TxSpecAmtChange()
(ActualSpecAmt
,minimum_specified_amount(0 == Year && 0 == Month,
TermRiderActive)
);
- ActualSpecAmt = round_specamt().c(ActualSpecAmt); // already
rounded?
+ ActualSpecAmt = round_specamt().c(ActualSpecAmt); // CURRENCY !!
already rounded?
InvariantValues().SpecAmt[j] = ActualSpecAmt;
if(!TermIsNotRider)
{
@@ -1128,10 +1118,15 @@ void AccountValue::TxTestGPT()
// TAXATION !! This assumes the term rider can be treated as death benefit;
// use 'TermIsDbFor7702'.
bool adj_event =
- (
- OldSA != ActualSpecAmt + TermSpecAmt
+#if defined USE_CURRENCY_CLASS
+ ( OldSA != ActualSpecAmt + TermSpecAmt
&& OldDB != DBReflectingCorr + TermDB
)
+#else // !defined USE_CURRENCY_CLASS
+ ( !materially_equal(OldSA, ActualSpecAmt + TermSpecAmt)
+ && !materially_equal(OldDB, DBReflectingCorr + TermDB)
+ )
+#endif // !defined USE_CURRENCY_CLASS
|| old_dbopt != new_dbopt
;
if(adj_event)
@@ -1152,7 +1147,7 @@ void AccountValue::TxTestGPT()
);
}
- // Already rounded by class Irc7702.
+ // CURRENCY !! already rounded by class Irc7702--appropriately?
GptForceout = round_minutiae().c(Irc7702_->Forceout());
// TODO ?? TAXATION !! On other bases, nothing is forced out, and payments
aren't limited.
process_distribution(GptForceout);
@@ -1223,16 +1218,6 @@ void AccountValue::TxAscertainDesiredPayment()
return;
}
- if(GrossPmts[Month] != EeGrossPmts[Month] + ErGrossPmts[Month])
- warning()
- << GrossPmts[Month] << " GrossPmts[Month]\n"
- << EeGrossPmts[Month] + ErGrossPmts[Month] << " EeGrossPmts[Month]
+ ErGrossPmts[Month]\n"
- << EeGrossPmts[Month] << " EeGrossPmts[Month]\n"
- << ErGrossPmts[Month] << " ErGrossPmts[Month]\n"
- << Year << " Year\n"
- << Month << " Month\n"
- << LMI_FLUSH
- ;
assert_pmts_add_up(__FILE__, __LINE__, Month);
currency eepmt = C0;
@@ -1242,6 +1227,7 @@ void AccountValue::TxAscertainDesiredPayment()
// Illustration-reg guaranteed premium ignores GPT limit.
if(!SolvingForGuarPremium)
{
+ // CURRENCY !! return modified value instead of altering argument
double z = dblize(eepmt);
Irc7702_->ProcessGptPmt(Year, z);
eepmt = round_gross_premium().c(z);
@@ -1257,6 +1243,7 @@ void AccountValue::TxAscertainDesiredPayment()
// Illustration-reg guaranteed premium ignores GPT limit.
if(!SolvingForGuarPremium)
{
+ // CURRENCY !! return modified value instead of altering argument
double z = dblize(erpmt);
Irc7702_->ProcessGptPmt(Year, z);
erpmt = round_gross_premium().c(z);
@@ -1265,18 +1252,10 @@ void AccountValue::TxAscertainDesiredPayment()
GrossPmts [Month] += erpmt;
}
- if(GrossPmts[Month] != EeGrossPmts[Month] + ErGrossPmts[Month])
- warning()
- << GrossPmts[Month] << " GrossPmts[Month]\n"
- << EeGrossPmts[Month] + ErGrossPmts[Month] << " EeGrossPmts[Month]
+ ErGrossPmts[Month]\n"
- << EeGrossPmts[Month] << " EeGrossPmts[Month]\n"
- << ErGrossPmts[Month] << " ErGrossPmts[Month]\n"
- << Year << " Year\n"
- << Month << " Month\n"
- << LMI_FLUSH
- ;
assert_pmts_add_up(__FILE__, __LINE__, Month);
- // bignum: the largest integer convertible to and from double.
+ // CURRENCY !! is this useful?
+ // bignum: the largest integer convertible to and from double
+ // such that incrementing it by one loses that property.
LMI_ASSERT(GrossPmts[Month] < from_cents(1LL << 53));
if(0 == Year && 0 == Month)
@@ -1284,6 +1263,7 @@ void AccountValue::TxAscertainDesiredPayment()
// Illustration-reg guaranteed premium ignores GPT limit.
if(!SolvingForGuarPremium)
{
+ // CURRENCY !! return modified value instead of altering argument
double z = dblize(Dumpin);
Irc7702_->ProcessGptPmt(Year, z);
Dumpin = round_gross_premium().c(z);
@@ -1322,6 +1302,8 @@ void AccountValue::TxLimitPayment(double a_maxpmt)
gross_1035 = External1035Amount + Internal1035Amount;
}
currency gross_pmt_without_1035 = GrossPmts[Month] - gross_1035;
+ // CURRENCY !! support infinities?
+// gross_pmt_without_1035 = std::min(gross_pmt_without_1035, a_maxpmt);
gross_pmt_without_1035 =
round_gross_premium().c(std::min(dblize(gross_pmt_without_1035), a_maxpmt));
// TODO ?? For now at least, reduce employee premium first.
progressively_limit
@@ -1404,14 +1386,6 @@ void AccountValue::TxAcceptPayment(currency a_pmt)
return;
}
- if(a_pmt < C0)
- warning()
- << a_pmt << " a_pmt\n"
- << Year << " Year\n"
- << Month << " Month\n"
-// << z << " z\n"
- << LMI_FLUSH
- ;
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.
@@ -1520,7 +1494,6 @@ currency AccountValue::GetPremLoad
;
LMI_ASSERT(0.0 <= sum_of_separate_loads);
-#if 1
double total_load =
target_portion * YearsTotLoadTgt
+ excess_portion * YearsTotLoadExc
@@ -1530,7 +1503,7 @@ currency AccountValue::GetPremLoad
( PremiumTax_->is_tiered()
|| materially_equal(total_load, sum_of_separate_loads)
);
-#endif // 0
+
return round_net_premium().c(sum_of_separate_loads);
}
@@ -1597,18 +1570,16 @@ void AccountValue::TxSetBOMAV()
LMI_ASSERT(C0 == term_specamt(0));
}
LMI_ASSERT(yare_input_.InforceSpecAmtLoadBase <= SpecAmtLoadLimit);
- SpecAmtLoadBase = round_specamt().c
- (
- std::min
- ( SpecAmtLoadLimit
- , (0 == Year && 0 == Month)
- ? dblize(std::max
- (term_specamt(0) + base_specamt(0)
- ,round_death_benefit().c(NetPmts[0] *
YearsCorridorFactor)
- ))
- : yare_input_.InforceSpecAmtLoadBase
+ SpecAmtLoadBase =
+ (0 == Year && 0 == Month)
+ ? std::max
+ (term_specamt(0) + base_specamt(0)
+ ,round_specamt().c(NetPmts[0] * YearsCorridorFactor)
)
- );
+ : round_specamt().c(yare_input_.InforceSpecAmtLoadBase)
+ ;
+ // CURRENCY !! support infinities?
+ SpecAmtLoadBase = round_specamt().c(std::min(dblize(SpecAmtLoadBase),
SpecAmtLoadLimit));
}
// These assignments must happen every month.
@@ -1723,7 +1694,7 @@ void AccountValue::TxSetDeathBft()
DB7702A = DBReflectingCorr + TermDB;
DcvDeathBft = std::max
- (dblize(DBIgnoringCorr)
+ ( dblize(DBIgnoringCorr)
, (
YearsCorridorFactor
* ( Dcv
@@ -1945,11 +1916,13 @@ void AccountValue::TxSetRiderDed()
YearsWpRate
* (
DcvCoiCharge
- + dblize(MonthsPolicyFees)
- + dblize(SpecAmtLoad)
- + dblize(AdbCharge)
- + dblize(SpouseRiderCharge)
- + dblize(ChildRiderCharge)
+ + dblize
+ ( MonthsPolicyFees
+ + SpecAmtLoad
+ + AdbCharge
+ + SpouseRiderCharge
+ + ChildRiderCharge
+ )
+ DcvTermCharge
);
}
@@ -2040,16 +2013,12 @@ void AccountValue::TxTestHoneymoonForExpiration()
if(HoneymoonValue <= C0 || HoneymoonValue < csv_ignoring_loan)
{
HoneymoonActive = false;
- // In 'master', this is
- // -std::numeric_limits<double>::max()
- // which is the identity element for std::max(). Here, it's nearly
- // the equivalent for currency::data_type; dividing it by 101 is a
- // casual defense against commuting between dollars and cents.
#if defined USE_CURRENCY_CLASS
- HoneymoonValue =
from_cents(-std::numeric_limits<currency::data_type>::max() / 101);
+ // CURRENCY !! support infinities?
+ 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
+#endif // !defined USE_CURRENCY_CLASS
}
}
@@ -2063,6 +2032,7 @@ void AccountValue::TxTakeSepAcctLoad()
{
if(SepAcctLoadIsDynamic)
{
+ // CURRENCY !! should class stratified_charges use currency?
double stratified_load = StratifiedCharges_->stratified_sepacct_load
(GenBasis_
,dblize(AssetsPostBom)
@@ -2098,7 +2068,7 @@ void AccountValue::TxTakeSepAcctLoad()
}
SepAcctLoad = round_interest_credit().c(YearsSepAcctLoadRate * AVSepAcct);
- // Does this seem right? Mightn't it take a sepacct load from the genacct?
+ // CURRENCY !! Does this seem right? Mightn't it take a sepacct load from
the genacct?
process_deduction(SepAcctLoad);
YearsTotalSepAcctLoad += SepAcctLoad;
Dcv -= dblize(SepAcctLoad);
@@ -2356,20 +2326,21 @@ currency AccountValue::anticipated_deduction
void AccountValue::SetMaxWD()
{
- double max_wd =
- AVGenAcct * MaxWdGenAcctValMult
- + AVSepAcct * MaxWdSepAcctValMult
- + dblize(AVRegLn + AVPrfLn)
- - dblize(RegLnBal + PrfLnBal)
- - dblize(anticipated_deduction(MaxWDDed_))
- - dblize(std::max(C0, SurrChg()))
+ MaxWD =
+ round_withdrawal().c
+ ( AVGenAcct * MaxWdGenAcctValMult
+ + AVSepAcct * MaxWdSepAcctValMult
+ )
+ + (AVRegLn + AVPrfLn)
+ - (RegLnBal + PrfLnBal)
+ - anticipated_deduction(MaxWDDed_)
+ - std::max(C0, SurrChg())
;
- if(max_wd < dblize(MinWD))
+ if(MaxWD < MinWD)
{
- max_wd = 0.0;
+ MaxWD = C0;
}
- max_wd = std::max(0.0, max_wd);
- MaxWD = round_withdrawal().c(max_wd);
+ MaxWD = std::max(C0, MaxWD);
}
/// Take a withdrawal.
@@ -2540,13 +2511,14 @@ void AccountValue::TxTakeWD()
return;
}
- GrossWD = round_withdrawal().c(dblize(NetWD) + std::min(dblize(WDFee),
NetWD * WDFeeRate));
+ GrossWD = NetWD + std::min(WDFee, round_withdrawal().c(NetWD * WDFeeRate));
// Free partial surrenders: for instance, the first 20% of account
// value might be withdrawn each policy year free of surrender
// charge. This would become more complicated if we maintained
// distinct surrender-charge layers.
+ // CURRENCY !! more efficient: currency / currency --> double
double surrchg_proportion = SurrChg_[Year] / dblize(csv);
currency non_free_wd = GrossWD;
if(0.0 != FreeWDProportion[Year])
@@ -2646,7 +2618,7 @@ void AccountValue::TxTakeWD()
{
// TODO ?? TAXATION !! What if reference argument
// 'premiums_paid_increment' is modified?
- double premiums_paid_increment = 0.0 - dblize(GrossWD);
+ double premiums_paid_increment = -dblize(GrossWD);
Irc7702_->ProcessGptPmt(Year, premiums_paid_increment);
}
}
@@ -2848,8 +2820,11 @@ void AccountValue::TxTestLapse()
( NoLapseMinAge <= Year + BasicValues::GetIssueAge()
&& NoLapseMinDur <= Year
|| CumPmts < CumNoLapsePrem
-// && !materially_equal(CumPmts, CumNoLapsePrem)
- && CumPmts != CumNoLapsePrem
+#if defined USE_CURRENCY_CLASS
+ // x<y --> x<>y for x,y integral
+#else // !defined USE_CURRENCY_CLASS
+ && !materially_equal(CumPmts, CumNoLapsePrem)
+#endif // !defined USE_CURRENCY_CLASS
)
{
NoLapseActive = false;
diff --git a/ihs_avsolve.cpp b/ihs_avsolve.cpp
index ec57dd6..1f2f18d 100644
--- a/ihs_avsolve.cpp
+++ b/ihs_avsolve.cpp
@@ -69,7 +69,7 @@ class SolveHelper
// or at least to make this function take a 'currency' argument.
double operator()(double a_CandidateValue)
{
-// CURRENCY !! Consider using zero<currency> instead of double.
+// CURRENCY !! Consider using decimal_root<currency> instead of double.
return dblize(av.SolveTest(av.round_minutiae().c(a_CandidateValue)));
}
};
@@ -221,7 +221,6 @@ currency AccountValue::SolveTest(currency a_CandidateValue)
// counters and iterators--it's one past the end--but indexing
// must decrement it.
// CURRENCY !! Cents in ledger will make rounding unnecessary.
-// currency value {VariantValues().CSVNet[SolveTargetDuration_ - 1]};
currency value =
round_minutiae().c(VariantValues().CSVNet[SolveTargetDuration_ - 1]);
if(mce_solve_for_target_naar == SolveTarget_)
{
@@ -251,8 +250,8 @@ currency AccountValue::SolveTest(currency a_CandidateValue)
if(mce_solve_for_non_mec == SolveTarget_)
{
- static const currency C1 = from_cents(100); // One hundred cents.
- return InvariantValues().IsMec ? -C1 : C1;
+ static const currency C100 = from_cents(100); // one dollar
+ return InvariantValues().IsMec ? -C100 : C100;
}
return value - SolveTargetCsv_;
@@ -379,11 +378,13 @@ 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 = dblize(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;
case mce_solve_ee_prem:
diff --git a/ihs_basicval.cpp b/ihs_basicval.cpp
index b63d368..2ff24a5 100644
--- a/ihs_basicval.cpp
+++ b/ihs_basicval.cpp
@@ -567,11 +567,10 @@ currency BasicValues::GetAnnualTgtPrem(int a_year,
currency a_specamt) const
void BasicValues::SetPermanentInvariants()
{
- // maybe implement query_into<currency>
- MinIssSpecAmt =
round_specamt().c(database().query<int>(DB_MinIssSpecAmt ));
- MinIssBaseSpecAmt =
round_specamt().c(database().query<int>(DB_MinIssBaseSpecAmt ));
- MinRenlSpecAmt =
round_specamt().c(database().query<int>(DB_MinRenlSpecAmt ));
- MinRenlBaseSpecAmt =
round_specamt().c(database().query<int>(DB_MinRenlBaseSpecAmt));
+ MinIssSpecAmt =
round_specamt().c(database().query<double>(DB_MinIssSpecAmt ));
+ MinIssBaseSpecAmt =
round_specamt().c(database().query<double>(DB_MinIssBaseSpecAmt ));
+ MinRenlSpecAmt =
round_specamt().c(database().query<double>(DB_MinRenlSpecAmt ));
+ MinRenlBaseSpecAmt =
round_specamt().c(database().query<double>(DB_MinRenlBaseSpecAmt));
database().query_into(DB_NoLapseDboLvlOnly , NoLapseDboLvlOnly);
database().query_into(DB_NoLapseUnratedOnly , NoLapseUnratedOnly);
database().query_into(DB_DboChgCanIncrSpecAmt , OptChgCanIncrSA);
@@ -585,18 +584,14 @@ void BasicValues::SetPermanentInvariants()
database().query_into(DB_TermForcedConvAge , TermForcedConvAge);
database().query_into(DB_TermForcedConvDur , TermForcedConvDur);
database().query_into(DB_ExpSpecAmtLimit , ExpPerKLimit);
-// NO! ExpPerKLimit = database().query<int>(DB_ExpSpecAmtLimit);
database().query_into(DB_MinPremType , MinPremType);
database().query_into(DB_TgtPremType , TgtPremType);
database().query_into(DB_TgtPremFixedAtIssue , TgtPremFixedAtIssue);
- TgtPremMonthlyPolFee =
round_gross_premium().c(database().query<int>(DB_TgtPremMonthlyPolFee));
+ TgtPremMonthlyPolFee =
round_gross_premium().c(database().query<double>(DB_TgtPremMonthlyPolFee));
// Assertion: see comments on GetModalPremTgtFromTable().
LMI_ASSERT(C0 == TgtPremMonthlyPolFee || oe_modal_table == TgtPremType);
database().query_into(DB_CurrCoiTable0Limit , CurrCoiTable0Limit);
database().query_into(DB_CurrCoiTable1Limit , CurrCoiTable1Limit);
-// NO!
-// CurrCoiTable0Limit = database().query<int>(DB_CurrCoiTable0Limit );
-// CurrCoiTable1Limit = database().query<int>(DB_CurrCoiTable1Limit );
LMI_ASSERT(0.0 <= CurrCoiTable0Limit);
LMI_ASSERT(CurrCoiTable0Limit <= CurrCoiTable1Limit);
database().query_into(DB_CoiInforceReentry , CoiInforceReentry);
@@ -612,11 +607,8 @@ void BasicValues::SetPermanentInvariants()
database().query_into(DB_AdbLimit , AdbLimit);
database().query_into(DB_WpLimit , WpLimit);
database().query_into(DB_SpecAmtLoadLimit , SpecAmtLoadLimit);
-// AdbLimit = database().query<int>(DB_AdbLimit );
-// WpLimit = database().query<int>(DB_WpLimit );
-// SpecAmtLoadLimit = database().query<int>(DB_SpecAmtLoadLimit);
- MinWD = round_withdrawal().c(database().query<int>(DB_MinWd));
- WDFee = round_withdrawal().c(database().query<int>(DB_WdFee));
+ MinWD = round_withdrawal().c(database().query<double>(DB_MinWd));
+ WDFee = round_withdrawal().c(database().query<double>(DB_WdFee));
database().query_into(DB_WdFeeRate , WDFeeRate);
database().query_into(DB_AllowChangeToDbo2 , AllowChangeToDBO2);
database().query_into(DB_AllowSpecAmtIncr , AllowSAIncr);
@@ -1157,6 +1149,10 @@ std::pair<double,double> BasicValues::approx_mly_ded
if(yare_input_.AccidentalDeathBenefit)
{
double const r = MortalityRates_->AdbRates()[year];
+ // CURRENCY !! Here and elsewhere in this file, consider
+ // letting currency objects assume infinite values--so that
+ // 'AdbLimit' could be of currency type, and dblize() would
+ // not be needed.
mly_ded += r * std::min(dblize(specamt), AdbLimit);
}
diff --git a/solve.cpp b/solve.cpp
index 124d906..3216232 100644
--- a/solve.cpp
+++ b/solve.cpp
@@ -98,8 +98,7 @@ currency SolveTest()
);
}
-// CURRENCY !! Cents in ledger will make rounding unnecessary.
-// currency z {ConstThat->VariantValues().CSVNet[ThatSolveTgtYear - 1]};
+ // 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);
@@ -158,7 +157,6 @@ currency SolveTest()
//============================================================================
inline static double SolveSpecAmt(double CandidateValue)
-//inline static double SolveSpecAmt(currency CandidateValue)
{
// IHS !! Change surrchg when SA changes?
That->SolveSetSpecAmt(round_to_cents.c(CandidateValue), ThatSolveBegYear,
ThatSolveEndYear);
@@ -167,7 +165,6 @@ inline static double SolveSpecAmt(double CandidateValue)
//============================================================================
inline static double SolvePrem(double CandidateValue)
-//inline static double SolvePrem(currency CandidateValue)
{
That->SolveSetPmts(round_to_cents.c(CandidateValue), ThatSolveBegYear,
ThatSolveEndYear);
return only_set_values ? 0.0 : dblize(SolveTest());
@@ -175,7 +172,6 @@ inline static double SolvePrem(double CandidateValue)
//============================================================================
inline static double SolveLoan(double CandidateValue)
-//inline static double SolveLoan(currency CandidateValue)
{
That->SolveSetLoans(round_to_cents.c(CandidateValue), ThatSolveBegYear,
ThatSolveEndYear);
return only_set_values ? 0.0 : dblize(SolveTest());
@@ -183,7 +179,6 @@ inline static double SolveLoan(double CandidateValue)
//============================================================================
inline static double SolveWD(double CandidateValue)
-//inline static double SolveWD(currency CandidateValue)
{
That->SolveSetWDs(round_to_cents.c(CandidateValue), ThatSolveBegYear,
ThatSolveEndYear);
return only_set_values ? 0.0 : dblize(SolveTest());
@@ -265,7 +260,6 @@ currency AccountValue::Solve()
}
double(*SolveFn)(double) = nullptr;
-// double(*SolveFn)(currency) = nullptr;
double LowerBound = 0.0;
double UpperBound = 0.0;
root_bias Bias = bias_higher;
@@ -358,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;
- currency const solution_cents = round_to_cents.c(Solution.first);
+ currency const solution_cents = round_to_cents.c(Solution.first);
SolveFn(dblize(solution_cents));
return solution_cents;
}
- [lmi-commits] [lmi] valyuta/005 updated (e7a64aa -> 731c6f5), Greg Chicares, 2021/01/28
- [lmi-commits] [lmi] valyuta/005 f9c5764 2/5: Resolve even more gratuitous incompatibilities with master, Greg Chicares, 2021/01/28
- [lmi-commits] [lmi] valyuta/005 e124445 4/5: Don't use currency when it must always be converted to double, Greg Chicares, 2021/01/28
- [lmi-commits] [lmi] valyuta/005 d5c50ee 1/5: Resolve more gratuitous incompatibilities with master,
Greg Chicares <=
- [lmi-commits] [lmi] valyuta/005 9c2b0ad 3/5: Make NAAR currency, not double, Greg Chicares, 2021/01/28
- [lmi-commits] [lmi] valyuta/005 731c6f5 5/5: Tear down temporary scaffolding that has served its purpose, Greg Chicares, 2021/01/28