[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
- [lmi-commits] [lmi] master updated (9e5a09bf -> 3903a0c3), Greg Chicares, 2022/05/09
- [lmi-commits] [lmi] master a1533521 01/13: Replace a history command, Greg Chicares, 2022/05/09
- [lmi-commits] [lmi] master 3903eed7 03/13: Include appropriate headers, and say why they're included, Greg Chicares, 2022/05/09
- [lmi-commits] [lmi] master d9c5f0d5 04/13: Use a local alias to shorten expressions, Greg Chicares, 2022/05/09
- [lmi-commits] [lmi] master 3d69769b 05/13: Demonstrate that a default comparison tolerance works well, Greg Chicares, 2022/05/09
- [lmi-commits] [lmi] master 4d7fe889 07/13: Use rate_times_currency(), Greg Chicares, 2022/05/09
- [lmi-commits] [lmi] master 03ad37d7 08/13: Note an arcanum, Greg Chicares, 2022/05/09
- [lmi-commits] [lmi] master a67210ec 10/13: Better explain the purpose of each block of unit tests, Greg Chicares, 2022/05/09
- [lmi-commits] [lmi] master ee272a29 02/13: Suppress certain GTK diagnostics, Greg Chicares, 2022/05/09
- [lmi-commits] [lmi] master c768da7e 06/13: Refactor, almost,
Greg Chicares <=
- [lmi-commits] [lmi] master 35eb8545 09/13: Prefer a calculation with less roundoff error, Greg Chicares, 2022/05/09
- [lmi-commits] [lmi] master c53ea12a 11/13: Reorder some statements in a unit test, Greg Chicares, 2022/05/09
- [lmi-commits] [lmi] master 8b6d6dd8 12/13: Say DECIMAL_DIG wherever it's meant, Greg Chicares, 2022/05/09
- [lmi-commits] [lmi] master 3903a0c3 13/13: Record speed measurements, Greg Chicares, 2022/05/09