[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[lmi-commits] [lmi] master 4d7fe889 07/13: Use rate_times_currency()
From: |
Greg Chicares |
Subject: |
[lmi-commits] [lmi] master 4d7fe889 07/13: Use rate_times_currency() |
Date: |
Mon, 9 May 2022 20:13:17 -0400 (EDT) |
branch: master
commit 4d7fe88977d1a7ab208d568ac520ff75fbae3fe1
Author: Gregory W. Chicares <gchicares@sbcglobal.net>
Commit: Gregory W. Chicares <gchicares@sbcglobal.net>
Use rate_times_currency()
Motivating example from an actual regression test:
0.00000250 specified-amount load
$250000 specified amount
In binary64 arithmetic, this is
0.00000250 * 250000 = 0.625 (approximately!)
which is to be rounded to the nearest or even cent; 62 and 63 cents are
equally near, but 62 is even, so the answer should be 62.
However, for the i686+x87 architecture still used in production for now,
the answer was sixty-three cents, evidently because of representation
error in "0.00000250", which is eradicated by shifting the decimal point
rightward to produce a rational number with a power-of-ten denominator.
In the worst regression between i686 and x86_64, this difference of one
cent in a monthly deduction grew to $79.19 at compound interest over 75
years. Reasonableness check: the implicit annual percentage rate is
9.04% = (79.19 / 0.12) ^ (1 / 75) - 1
which is acceptably close to the 7.46% separate-account rate illustrated
(the rates wouldn't be exactly the same because the account-value
calculation has many other components). That case represented the
largest discrepancy in absolute terms; with this commit, it matches on
both i686 and x86_64 to within 1e-12 dollars.
This is no mere pedantic quibble: US courts have entertained lawsuits
concerning the rounding of insurance rates. See, for example, the
following cases in the Zavala County Texas District Court:
- 95-08-09169-CV Martinez v. Allstate Insurance Co.
- 95-08-09165-CV Sendejo v. Texas Farmers Insurance Co.
---
ihs_avmly.cpp | 7 ++++++-
ul_utilities_test.cpp | 25 +++++++++++++++++++++++++
2 files changed, 31 insertions(+), 1 deletion(-)
diff --git a/ihs_avmly.cpp b/ihs_avmly.cpp
index 7c3e6f04..f1cbb700 100644
--- a/ihs_avmly.cpp
+++ b/ihs_avmly.cpp
@@ -44,6 +44,7 @@
#include "premium_tax.hpp"
#include "stratified_algorithms.hpp"
#include "stratified_charges.hpp"
+#include "ul_utilities.hpp" // rate_times_currency()
#include <algorithm> // min(), max()
#include <cmath> // pow()
@@ -1664,7 +1665,11 @@ void AccountValue::TxSetBOMAV()
}
YearsTotalPolicyFee += MonthsPolicyFees;
- SpecAmtLoad = round_minutiae().c(YearsSpecAmtLoadRate * SpecAmtLoadBase);
+ SpecAmtLoad = rate_times_currency
+ (YearsSpecAmtLoadRate
+ ,SpecAmtLoadBase
+ ,round_minutiae()
+ );
YearsTotalSpecAmtLoad += SpecAmtLoad;
process_deduction(MonthsPolicyFees + SpecAmtLoad);
diff --git a/ul_utilities_test.cpp b/ul_utilities_test.cpp
index a7c07d9d..683aa21e 100644
--- a/ul_utilities_test.cpp
+++ b/ul_utilities_test.cpp
@@ -68,6 +68,31 @@ void test_max_modal_premium()
round_to<double> const round_not (2, r_not_at_all);
round_to<double> const round_up (2, r_upward);
+ // Motivating example from an actual regression test:
+ // 0.00000250 specified-amount load
+ // $250000 specified amount
+ // In binary64 arithmetic, this is
+ // 0.00000250 * 250000 = 0.625 (approximately!)
+ // which is to be rounded to the nearest or even cent; 62 and 63 cents are
+ // equally near, but 62 is even, so the answer should be 62.
+ // However, for the i686+x87 architecture still used in production for now,
+ // the answer was sixty-three cents, evidently because of representation
+ // error in "0.00000250", which is eradicated by shifting the decimal point
+ // rightward to produce a rational number with a power-of-ten denominator.
+ currency a00 = max_modal_premium
+ (0.00000250
+ ,250'000'00_cents
+ ,mce_annual
+ ,round_near
+ );
+ LMI_TEST_EQUAL(62_cents, a00);
+ // This fails for i686 (x87), which calculates 0.63 even though
+ // rounding mode is "nearer or even" and 62 cents is even:
+// LMI_TEST_EQUAL(0.62, round_near(0.00000250 * 250'000'00_cents));
+ // In the worst regression between i686 and x86_64, this difference of one
+ // cent in a monthly deduction grew to $79.19 at compound interest over 75
+ // years. Reasonableness check: the implicit annual percentage rate is
+
double const rate {0.0123456700000001};
currency const specamt {9'876'543'21_cents};
- [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 <=
- [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, 2022/05/09
- [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