lmi-commits
[Top][All Lists]
Advanced

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

[lmi-commits] [lmi] master 5a83dbc3 3/5: Augment unit test


From: Greg Chicares
Subject: [lmi-commits] [lmi] master 5a83dbc3 3/5: Augment unit test
Date: Sat, 14 May 2022 16:07:54 -0400 (EDT)

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

    Augment unit test
---
 ul_utilities_test.cpp | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 50 insertions(+)

diff --git a/ul_utilities_test.cpp b/ul_utilities_test.cpp
index 775ec42b..bebf8b85 100644
--- a/ul_utilities_test.cpp
+++ b/ul_utilities_test.cpp
@@ -32,6 +32,7 @@
 #include <cfloat>                       // DECIMAL_DIG
 #include <cmath>                        // nearbyint()
 #include <cstdint>                      // uint64_t
+#include <string>
 
 void test_max_modal_premium()
 {
@@ -100,6 +101,55 @@ void test_max_modal_premium()
         );
     LMI_TEST_EQUAL(62_cents, m00);
 
+    // Example of fallback to floating point, from an actual regression test:
+    //     184467440737 = ⌊UINT64_MAX / 1.0e8⌋
+    //   $ 1844674407.37 cents_limit, as dollars and cents
+    //   $24534504428.00 amount (exceeds cents_limit)
+    //    0.055394150000000003109 rate
+    //     1359068018.46029639244 amount * rate: floating-point calculation
+    //     1359068018.46029620    amount * rate: exact fixed-point answer
+    currency n00 = rate_times_currency
+        (0.05539415
+        ,24534504428'00_cents
+        ,round_near
+        );
+    LMI_TEST_EQUAL(1'359'068'018'46_cents, n00);
+    // The 1359068018.46 rounded-near answer that would ideally be desired
+    // is representable as an exact number of cents, and the product
+    //   5539415 * 24534504428 = 135906801846029620
+    // actually can be calculated exactly in 64-bit integer arithmetic:
+    LMI_TEST_EQUAL  (135906801846029620ULL, 5539415ULL * 24534504428ULL);
+    //             18446744073709551615ULL = UINT64_MAX
+    LMI_TEST        (135906801846029620ULL < UINT64_MAX);
+    // and can even be divided by 1000000 to get (truncated) cents:
+    LMI_TEST_EQUAL  (135906801846ULL, 5539415ULL * 24534504428ULL / 1000000);
+    // but that exceeds the precision of binary64 arithmetic:
+    //                 9007199254740991 = (1ULL << 53) - 1
+    // (so 135906801846029616 is the (inaccurate) answer that a spreadsheet
+    // would most likely offer. This naive test:
+//  LMI_TEST_UNEQUAL(135906801846029620.0, 5539415.0 * 24534504428.0);
+    // may succeed or fail, but this one should be more accurate:
+    std::string product_str = std::to_string(5539415.0 * 24534504428.0);
+    LMI_TEST_UNEQUAL("135906801846029620", product_str);
+    // ).
+    //
+    // Given that an exact integer calculation can be performed in
+    // this case, why is that not done? The reason is that the choice
+    // is made using a fast but slightly coarse test that ignores the
+    // value of 'rate' and the actual precision of 'amount', regarding
+    // the problem:
+    //   $24534504428.00 amount
+    //        0.05539415 rate
+    // as though it were:
+    //   $24534504428.99 amount (exceeds cents_limit)
+    //        0.99999999 rate
+    // which cannot be performed in 64-bit integer arithmetic, as may
+    // be grasped intuitively by concatenating the significant digits
+    // and comparing to UINT64_MAX:
+    //    245345044289999999999 concatenation
+    //    \--amount---/\-rate-/
+    //     18446744073709551615 UINT64_MAX
+
     // Test a rate and a specamt that use maximal precision,
     // because so many real-world examples are along the lines of
     // 0.01 * $100,000 .



reply via email to

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