lmi-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[lmi-commits] [lmi] master c768da7e 06/13: Refactor, almost


From: Greg Chicares
Subject: [lmi-commits] [lmi] master c768da7e 06/13: Refactor, almost
Date: Mon, 9 May 2022 20:13:17 -0400 (EDT)

branch: master
commit c768da7e9013b7964de186f32aff26e8410191f2
Author: Gregory W. Chicares <gchicares@sbcglobal.net>
Commit: Gregory W. Chicares <gchicares@sbcglobal.net>

    Refactor, almost
    
    In life insurance, many rates are given in tables with a fixed number of
    decimal places, and are stored as binary64 floating-point values because
    that seems natural, yet are thought of as exact rational numbers whose
    denominators are a small integral number of ten. Thus, in the example
    discussed in commit f97235aed48a52, multiplying $100000.00 by 4.90 and
    rounding up to the next dollar would give $490001 in floating-point
    arithmetic, but that was considered glaringly wrong: instead, it is
    considered exclusively correct to calculate 100000 * 490 / 100 in
    rational integer arithmetic. Such cases abound.
    
    Factored a new rate_times_currency() out of max_modal_premium() for
    general use.
    
    Reimplemented max_modal_premium() in terms of rate_times_currency().
    This is a refactoring except in the case that the rate is given to more
    than eight decimals, which is uncommon. In that case, no attempt is made
    to recover the notional fixed-precision rational number that the rate is
    taken to represent, and binary64 arithmetic is performed as formerly,
    but with division by the modal factor {1, 2, 4, 12} applied after the
    multiplication. This can make a difference in binary64 arithmetic, but
    it makes the answer more correct for reasons explained inline in the
    max_modal_premium() function. However, no regression is observed in
    practice, so writing this paragraph was hardly worthwhile.
---
 ul_utilities.cpp | 19 +++++++++++++++----
 ul_utilities.hpp |  6 ++++++
 2 files changed, 21 insertions(+), 4 deletions(-)

diff --git a/ul_utilities.cpp b/ul_utilities.cpp
index e8bae50c..8e681e6c 100644
--- a/ul_utilities.cpp
+++ b/ul_utilities.cpp
@@ -95,10 +95,9 @@ double list_bill_premium
     return std::inner_product(p0.begin(), p0.end(), v.begin(), 0.0);
 }
 
-currency max_modal_premium
+currency rate_times_currency
     (double                  rate
     ,currency                specamt
-    ,mcenum_mode             mode
     ,round_to<double> const& rounder
     )
 {
@@ -135,7 +134,7 @@ currency max_modal_premium
             << std::flush
             ;
 #endif // 0
-        return rounder.c(specamt * rate / mode);
+        return rounder.c(specamt * rate);
         }
 #if 0
     // Enable this assertion, adjusting the tolerance (last) argument
@@ -156,11 +155,23 @@ currency max_modal_premium
     // rounded floating-point division may give the wrong answer.
     int64 quotient  = iprod / radix;
     int64 remainder = iprod % radix;
-    currency const annual_premium =
+    return
         ((0 == remainder)
         ? from_cents(bourn_cast<double>(quotient))
         : rounder.c(cprod / radix)
         );
+}
+
+currency max_modal_premium
+    (double                  rate
+    ,currency                specamt
+    ,mcenum_mode             mode
+    ,round_to<double> const& rounder
+    )
+{
+    using int64 = std::int64_t;
+
+    currency const annual_premium = rate_times_currency(rate, specamt, 
rounder);
     // Calculate modal premium from annual as a separate step,
     // using integer division to discard any fractional part.
     // In a sense, this is double rounding, which is often a
diff --git a/ul_utilities.hpp b/ul_utilities.hpp
index 6c748535..af485310 100644
--- a/ul_utilities.hpp
+++ b/ul_utilities.hpp
@@ -39,6 +39,12 @@ double list_bill_premium
     ,double               v12
     );
 
+currency rate_times_currency
+    (double                  rate
+    ,currency                specamt
+    ,round_to<double> const& rounder
+    );
+
 currency max_modal_premium
     (double                  rate
     ,currency                specamt



reply via email to

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