lmi-commits
[Top][All Lists]
Advanced

[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 "



reply via email to

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