lmi-commits
[Top][All Lists]
Advanced

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

[lmi-commits] [lmi] valyuta/005 e40980b 05/10: Optionally detect noninte


From: Greg Chicares
Subject: [lmi-commits] [lmi] valyuta/005 e40980b 05/10: Optionally detect nonintegral cents at run time
Date: Thu, 21 Jan 2021 17:48:15 -0500 (EST)

branch: valyuta/005
commit e40980b3020f3912a91e3cfa97a4355e44b78dce
Author: Gregory W. Chicares <gchicares@sbcglobal.net>
Commit: Gregory W. Chicares <gchicares@sbcglobal.net>

    Optionally detect nonintegral cents at run time
    
    This test is costly and should normally be suppressed. Precondition
    validation isn't suppressed elsewhere in lmi; this case is different
    because the deliberately cumbersome explicit ctor is almost never used
    except with an argument that has just been rounded to an exact integral
    value. This is just a transitional aid until "almost never" becomes
    "never".
    
    The 'Speed*' files show the cost for solve-heavy tests to be about six
    or seven percent for x86_64, and sixteen or seventeen percent for i686.
---
 Speed_gcc_i686-w64-mingw32    | 12 ++++++------
 Speed_gcc_x86_64-pc-linux-gnu | 12 ++++++------
 Speed_gcc_x86_64-w64-mingw32  | 12 ++++++------
 currency.hpp                  | 18 +++++++++++++++---
 currency_test.cpp             | 17 ++++++++++++-----
 5 files changed, 45 insertions(+), 26 deletions(-)

diff --git a/Speed_gcc_i686-w64-mingw32 b/Speed_gcc_i686-w64-mingw32
index 1c75cd7..92be5a8 100644
--- a/Speed_gcc_i686-w64-mingw32
+++ b/Speed_gcc_i686-w64-mingw32
@@ -1,7 +1,7 @@
 Test speed:
-  naic, no solve      : 5.497e-02 s mean;      52960 us least of  19 runs
-  naic, specamt solve : 9.961e-02 s mean;      98756 us least of  11 runs
-  naic, ee prem solve : 9.104e-02 s mean;      89993 us least of  11 runs
-  finra, no solve     : 1.662e-02 s mean;      16412 us least of  61 runs
-  finra, specamt solve: 5.865e-02 s mean;      58050 us least of  18 runs
-  finra, ee prem solve: 5.406e-02 s mean;      53527 us least of  19 runs
+  naic, no solve      : 6.283e-02 s mean;      62216 us least of  16 runs
+  naic, specamt solve : 1.158e-01 s mean;     115250 us least of   9 runs
+  naic, ee prem solve : 1.053e-01 s mean;     104619 us least of  10 runs
+  finra, no solve     : 1.770e-02 s mean;      17407 us least of  57 runs
+  finra, specamt solve: 6.567e-02 s mean;      65102 us least of  16 runs
+  finra, ee prem solve: 6.045e-02 s mean;      59822 us least of  17 runs
diff --git a/Speed_gcc_x86_64-pc-linux-gnu b/Speed_gcc_x86_64-pc-linux-gnu
index 66dd9a3..5bb8ad4 100644
--- a/Speed_gcc_x86_64-pc-linux-gnu
+++ b/Speed_gcc_x86_64-pc-linux-gnu
@@ -1,7 +1,7 @@
 Test speed:
-  naic, no solve      : 2.124e-02 s mean;      20219 us least of  48 runs
-  naic, specamt solve : 3.703e-02 s mean;      36600 us least of  28 runs
-  naic, ee prem solve : 3.373e-02 s mean;      33333 us least of  30 runs
-  finra, no solve     : 5.945e-03 s mean;       5678 us least of 100 runs
-  finra, specamt solve: 2.094e-02 s mean;      20673 us least of  48 runs
-  finra, ee prem solve: 1.943e-02 s mean;      19163 us least of  52 runs
+  naic, no solve      : 2.228e-02 s mean;      21562 us least of  45 runs
+  naic, specamt solve : 3.938e-02 s mean;      38908 us least of  26 runs
+  naic, ee prem solve : 3.572e-02 s mean;      35374 us least of  28 runs
+  finra, no solve     : 6.131e-03 s mean;       5817 us least of 100 runs
+  finra, specamt solve: 2.200e-02 s mean;      21553 us least of  46 runs
+  finra, ee prem solve: 2.026e-02 s mean;      19766 us least of  50 runs
diff --git a/Speed_gcc_x86_64-w64-mingw32 b/Speed_gcc_x86_64-w64-mingw32
index c270e75..f4554d9 100644
--- a/Speed_gcc_x86_64-w64-mingw32
+++ b/Speed_gcc_x86_64-w64-mingw32
@@ -1,7 +1,7 @@
 Test speed:
-  naic, no solve      : 2.750e-02 s mean;      27221 us least of  37 runs
-  naic, specamt solve : 4.707e-02 s mean;      46764 us least of  22 runs
-  naic, ee prem solve : 4.326e-02 s mean;      42926 us least of  24 runs
-  finra, no solve     : 1.043e-02 s mean;      10253 us least of  96 runs
-  finra, specamt solve: 2.825e-02 s mean;      27989 us least of  36 runs
-  finra, ee prem solve: 2.625e-02 s mean;      26057 us least of  39 runs
+  naic, no solve      : 2.955e-02 s mean;      29217 us least of  34 runs
+  naic, specamt solve : 5.044e-02 s mean;      49875 us least of  20 runs
+  naic, ee prem solve : 4.615e-02 s mean;      45675 us least of  22 runs
+  finra, no solve     : 1.073e-02 s mean;      10507 us least of  94 runs
+  finra, specamt solve: 2.965e-02 s mean;      29297 us least of  34 runs
+  finra, ee prem solve: 2.767e-02 s mean;      27244 us least of  37 runs
diff --git a/currency.hpp b/currency.hpp
index 45e11d7..b94c9d2 100644
--- a/currency.hpp
+++ b/currency.hpp
@@ -24,7 +24,9 @@
 
 #include "config.hpp"
 
+#include <cmath>                        // rint()
 #include <ostream>
+#include <stdexcept>                    // runtime_error
 #include <vector>
 
 // Macros USE_CURRENCY_CLASS and CURRENCY_UNIT_IS_CENTS are used
@@ -35,6 +37,7 @@
 
 #if !defined USE_CURRENCY_CLASS
 #   undef CURRENCY_UNIT_IS_CENTS // Requires currency class.
+#   undef DETECT_NONINTEGRAL_CENTS // Meaningful only with currency class.
 
 using currency = double;
 
@@ -50,6 +53,7 @@ inline std::vector<double> dblize(std::vector<currency> 
const& z)
 #else // defined USE_CURRENCY_CLASS
 
 #   define CURRENCY_UNIT_IS_CENTS
+#   define DETECT_NONINTEGRAL_CENTS
 
 class raw_cents {}; // Tag class.
 
@@ -75,7 +79,17 @@ class currency
     currency& operator=(currency const&) = default;
     ~currency() = default;
 
-    explicit currency(data_type z, raw_cents) : m_ {z} {assert_integral(z);}
+    explicit currency(data_type z, raw_cents) : m_ {z}
+        {
+#   if defined DETECT_NONINTEGRAL_CENTS
+        // CURRENCY !! Consider removing this test altogether, and
+        // making the explicit ctor private so that only friend
+        // template class round_to can use it (with arguments that
+        // are certainly exact integers because they have just been
+        // rounded).
+        if(z != std::rint(z)) throw std::runtime_error("Nonintegral cents.");
+#   endif // defined DETECT_NONINTEGRAL_CENTS
+        }
 
     currency& operator+=(currency z) {m_ += z.m_; return *this;}
     currency& operator-=(currency z) {m_ -= z.m_; return *this;}
@@ -88,8 +102,6 @@ class currency
     double d() const {return m_ / cents_per_dollar;}
 
   private:
-    // CURRENCY !! Actually implement this.
-    void assert_integral(data_type) {}
     data_type m_ = {};
 };
 
diff --git a/currency_test.cpp b/currency_test.cpp
index 5393d6d..897534b 100644
--- a/currency_test.cpp
+++ b/currency_test.cpp
@@ -99,6 +99,16 @@ void currency_test::test_explicit_ctor()
 {
     currency const a1(325, raw_cents{});
     BOOST_TEST_EQUAL( 325, a1.m_);
+#if defined DETECT_NONINTEGRAL_CENTS
+    // 1/64 is an exact binary constant, so 100/64 cents could be
+    // converted to 1/64 dollars and back without loss of precision;
+    // but that's outside the intended scope of the currency class.
+    BOOST_TEST_THROW
+        ((currency {1.5625, raw_cents {}})
+        ,std::runtime_error
+        ,"Nonintegral cents."
+        );
+#endif // defined DETECT_NONINTEGRAL_CENTS
 }
 
 void currency_test::test_negation()
@@ -179,13 +189,10 @@ void currency_test::test_relops()
 
 void currency_test::test_stream_inserter()
 {
-    // 1/64 is an exact binary constant, with so few digits that it
-    // must print with full precision by default. However, it's not
-    // integral, and therefore probably should be forbidden.
-    currency const a3 {0.015625, raw_cents {}};
+    currency const a3 {123456, raw_cents {}};
     std::ostringstream oss;
     oss << a3;
-    BOOST_TEST_EQUAL("0.00015625", oss.str());
+    BOOST_TEST_EQUAL("1234.56", oss.str());
 }
 
 void currency_test::test_dollars()



reply via email to

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