[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[lmi-commits] [lmi] master 84e96df: Implement, test, and use non-curtate
From: |
Greg Chicares |
Subject: |
[lmi-commits] [lmi] master 84e96df: Implement, test, and use non-curtate years_and_months_since() |
Date: |
Sat, 24 Jun 2017 10:10:59 -0400 (EDT) |
branch: master
commit 84e96df6f46560e957d9ae54a27aed657214de15
Author: Gregory W. Chicares <address@hidden>
Commit: Gregory W. Chicares <address@hidden>
Implement, test, and use non-curtate years_and_months_since()
See:
http://lists.nongnu.org/archive/html/lmi/2017-06/msg00005.html
---
calendar_date.cpp | 39 ++++++++++++++++------
calendar_date_test.cpp | 87 ++++++++++++++++++++++++++++++++++++++++++++++----
financial.cpp | 2 +-
ihs_acctval.cpp | 22 +++----------
4 files changed, 116 insertions(+), 34 deletions(-)
diff --git a/calendar_date.cpp b/calendar_date.cpp
index 2ecd58d..3fb0283 100644
--- a/calendar_date.cpp
+++ b/calendar_date.cpp
@@ -504,17 +504,29 @@ int attained_age
return notional_age(birthdate, as_of_date, alb_anb);
}
-/// Full curtate years and months by which 'other_date' follows 'base_date'.
+/// Years and months by which 'other_date' follows 'base_date'.
///
-/// Throws if 'other_date' precedes 'base_date'.
+/// Depending on 'is_curtate', adding the result to 'base_date' thus:
+/// add_years_and_months(base_date, result.first, result.second, true)
+/// yields the closest monthiversary M of 'base_date' such that
+/// [is_curtate] M <= other_date
+/// [otherwise] other_date <= M
+///
+/// Precondition: 'other_date' <= 'base_date'; throws if violated.
///
/// Postconditions:
/// 0 <= months < 12
-/// and
-/// a <= other_date < b
-/// for calendar dates a, b such that
-/// a = add_years_and_months(base_date, years, months, true)
-/// b = add_years_and_months(base_date, years, 1 + months, true)
+/// and exactly one of the following:
+///
+/// if 'is_curtate', then (counting only full curtate months):
+/// a <= other_date < b, for calendar dates a, b such that
+/// a = add_years_and_months(base_date, years, months , true)
+/// b = add_years_and_months(base_date, years, months + 1, true)
+///
+/// otherwise (counting any partial month as well):
+/// a < other_date <= b, for calendar dates a, b such that
+/// a = add_years_and_months(base_date, years, months - 1, true)
+/// b = add_years_and_months(base_date, years, months , true)
std::pair<int,int> years_and_months_since
(calendar_date const& base_date
@@ -522,7 +534,6 @@ std::pair<int,int> years_and_months_since
,bool is_curtate
)
{
-(void)&is_curtate;
if(other_date < base_date)
{
alarum()
@@ -542,12 +553,22 @@ std::pair<int,int> years_and_months_since
int months = mdiff % 12;
calendar_date z = add_years_and_months(base_date, years, months, true);
- if(other_date < z)
+ if(is_curtate && other_date < z)
{
--mdiff;
years = mdiff / 12;
months = mdiff % 12;
}
+ else if(!is_curtate && z < other_date)
+ {
+ ++mdiff;
+ years = mdiff / 12;
+ months = mdiff % 12;
+ }
+ else
+ {
+ // Do nothing: postconditions have already been established.
+ }
LMI_ASSERT(0 <= years);
LMI_ASSERT(0 <= months && months < 12);
diff --git a/calendar_date_test.cpp b/calendar_date_test.cpp
index ee2783c..ba286d8 100644
--- a/calendar_date_test.cpp
+++ b/calendar_date_test.cpp
@@ -752,6 +752,68 @@ void CalendarDateTest::TestIntegralDuration()
BOOST_TEST_EQUAL(-2, duration_floor (base_date, other_date));
BOOST_TEST_EQUAL(-1, duration_ceiling(base_date, other_date));
+ // Test years_and_months_since()'s 'is_curtate' argument.
+
+ base_date = calendar_date(2000, 1, 1);
+ other_date = calendar_date(2001, 1, 15);
+ // Curtate: count full months completed during interval.
+ ym = years_and_months_since(base_date, other_date, true);
+ BOOST_TEST_EQUAL( 1, ym.first );
+ BOOST_TEST_EQUAL( 0, ym.second);
+ // Not curtate: count months begun during interval.
+ ym = years_and_months_since(base_date, other_date, false);
+ BOOST_TEST_EQUAL( 1, ym.first );
+ BOOST_TEST_EQUAL( 1, ym.second);
+
+ base_date = calendar_date(2000, 1, 15);
+ other_date = calendar_date(2001, 2, 1);
+ ym = years_and_months_since(base_date, other_date, true);
+ BOOST_TEST_EQUAL( 1, ym.first );
+ BOOST_TEST_EQUAL( 0, ym.second);
+ ym = years_and_months_since(base_date, other_date, false);
+ BOOST_TEST_EQUAL( 1, ym.first );
+ BOOST_TEST_EQUAL( 1, ym.second);
+
+ // Curtate == non-curtate for identical dates.
+ base_date = calendar_date(2000, 1, 1);
+ other_date = calendar_date(2000, 1, 1);
+ ym = years_and_months_since(base_date, other_date, true);
+ BOOST_TEST_EQUAL( 0, ym.first );
+ BOOST_TEST_EQUAL( 0, ym.second);
+ ym = years_and_months_since(base_date, other_date, false);
+ BOOST_TEST_EQUAL( 0, ym.first );
+ BOOST_TEST_EQUAL( 0, ym.second);
+
+ // Curtate == non-curtate for exact monthiversaries.
+ base_date = calendar_date(2000, 1, 1);
+ other_date = calendar_date(2001, 2, 1);
+ ym = years_and_months_since(base_date, other_date, true);
+ BOOST_TEST_EQUAL( 1, ym.first );
+ BOOST_TEST_EQUAL( 1, ym.second);
+ ym = years_and_months_since(base_date, other_date, false);
+ BOOST_TEST_EQUAL( 1, ym.first );
+ BOOST_TEST_EQUAL( 1, ym.second);
+
+ // Interval beginning on leap-year day.
+ base_date = calendar_date(2000, 2, 29);
+ other_date = calendar_date(2001, 1, 1);
+ ym = years_and_months_since(base_date, other_date, true);
+ BOOST_TEST_EQUAL( 0, ym.first );
+ BOOST_TEST_EQUAL(10, ym.second);
+ ym = years_and_months_since(base_date, other_date, false);
+ BOOST_TEST_EQUAL( 0, ym.first );
+ BOOST_TEST_EQUAL(11, ym.second);
+
+ // Interval ending on leap-year day.
+ base_date = calendar_date(2000, 1, 1);
+ other_date = calendar_date(2000, 2, 29);
+ ym = years_and_months_since(base_date, other_date, true);
+ BOOST_TEST_EQUAL( 0, ym.first );
+ BOOST_TEST_EQUAL( 1, ym.second);
+ ym = years_and_months_since(base_date, other_date, false);
+ BOOST_TEST_EQUAL( 0, ym.first );
+ BOOST_TEST_EQUAL( 2, ym.second);
+
// Demonstrate strong noncommutativity. To show that
// duration_floor(X, Y)
// -duration_floor(Y, X)
@@ -797,13 +859,24 @@ void
CalendarDateTest::TestYearAndMonthDifferenceExhaustively()
;++e
)
{
- std::pair<int,int> ym = years_and_months_since(d, e, true);
- int y = ym.first;
- int m = ym.second;
- calendar_date a = add_years_and_months(d, y, m, true);
- calendar_date b = add_years_and_months(d, y, 1 + m, true);
- LMI_ASSERT(a <= e );
- LMI_ASSERT( e < b);
+ {
+ std::pair<int,int> ym = years_and_months_since(d, e, true);
+ int y = ym.first;
+ int m = ym.second;
+ calendar_date a = add_years_and_months(d, y, m , true);
+ calendar_date b = add_years_and_months(d, y, m + 1, true);
+ LMI_ASSERT(a <= e );
+ LMI_ASSERT( e < b);
+ }
+ {
+ std::pair<int,int> ym = years_and_months_since(d, e, false);
+ int y = ym.first;
+ int m = ym.second;
+ calendar_date a = add_years_and_months(d, y, m - 1, true);
+ calendar_date b = add_years_and_months(d, y, m , true);
+ LMI_ASSERT(a < e );
+ LMI_ASSERT( e <= b);
+ }
}
}
}
diff --git a/financial.cpp b/financial.cpp
index 3cf7cef..3d14d46 100644
--- a/financial.cpp
+++ b/financial.cpp
@@ -73,7 +73,7 @@ double list_bill_premium
if(bill_date < cert_date) return 0.0;
// Number of alpha months in the twelvemonth starting on bill date.
int const inforce_months_mod_12 = years_and_months_since
- (cert_date, bill_date, true).second
+ (cert_date, bill_date, false).second
;
// Number of delta months in the twelvemonth starting on bill date.
int const months_ante = 12 - inforce_months_mod_12;
diff --git a/ihs_acctval.cpp b/ihs_acctval.cpp
index f46cbf5..1e19c08 100644
--- a/ihs_acctval.cpp
+++ b/ihs_acctval.cpp
@@ -1134,9 +1134,6 @@ double AccountValue::ModalMinInitPremShortfall() const
/// The year and month of determination correspond to the first
/// monthiversary on or after the list-bill date. If there is no
/// such monthiversary, then harmless default values are used.
-///
-/// SOMEDAY !! Add a calendar_date function to return 'b' directly
-/// instead of incrementing the number of months conditionally.
void AccountValue::set_list_bill_year_and_month()
{
@@ -1144,23 +1141,15 @@ void AccountValue::set_list_bill_year_and_month()
auto const& bill_date = yare_input_.ListBillDate;
if(bill_date < cert_date) return;
- auto z = years_and_months_since(cert_date, bill_date, true);
- auto const a = add_years_and_months(cert_date, z.first, z.second, true);
- if(a < bill_date)
- {
- ++z.second;
- }
- auto const b = add_years_and_months(cert_date, z.first, z.second, true);
- LMI_ASSERT(cert_date <= b);
+ auto const z = years_and_months_since(cert_date, bill_date, false);
list_bill_year_ = z.first;
list_bill_month_ = z.second;
if(!contains(yare_input_.Comments, "idiosyncrasyL")) return;
// Temporary supplemental code for acceptance testing.
- int const inforce_months_mod_12 = years_and_months_since
- (cert_date, bill_date, true).second
- ;
+ auto const a = add_years_and_months(cert_date, z.first, z.second, true);
+ int const inforce_months_mod_12 = z.second;
// Number of delta months in the twelvemonth starting on bill date.
int const months_ante = 12 - inforce_months_mod_12;
warning()
@@ -1168,11 +1157,10 @@ void AccountValue::set_list_bill_year_and_month()
<< yare_input_.ListBillDate.str() << " yare_input_.ListBillDate\n"
<< list_bill_year_ << " list_bill_year_\n"
<< list_bill_month_ << " list_bill_month_\n"
- << a.str() << " a = speculative determination date\n"
- << b.str() << " b = actual determination date\n"
+ << a.str() << " a = premium determination date\n"
<< months_ante << " months_ante\n"
<< "List-bill premium will be set in monthiversary processing on "
- << b.str() << ", which is "
+ << a.str() << ", which is "
<< list_bill_year_ << " years and " << list_bill_month_ << " months"
<< " after the issue date. An annual-mode list bill will reflect this"
<< " premium for "
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [lmi-commits] [lmi] master 84e96df: Implement, test, and use non-curtate years_and_months_since(),
Greg Chicares <=