lmi-commits
[Top][All Lists]
Advanced

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

[lmi-commits] [lmi] valyuta/002 0e8c429 12/65: rounding


From: Greg Chicares
Subject: [lmi-commits] [lmi] valyuta/002 0e8c429 12/65: rounding
Date: Wed, 16 Sep 2020 16:55:13 -0400 (EDT)

branch: valyuta/002
commit 0e8c429e4e041d3388a46154076d009b739b5130
Author: Gregory W. Chicares <gchicares@sbcglobal.net>
Commit: Gregory W. Chicares <gchicares@sbcglobal.net>

    rounding
---
 currency.hpp       | 31 +++++++++++++++++++------------
 death_benefits.cpp |  8 ++++----
 outlay.cpp         | 18 +++++++++---------
 round_to.hpp       | 27 +++++++++++++++++++++++++++
 round_to_test.cpp  |  7 +++++++
 5 files changed, 66 insertions(+), 25 deletions(-)

diff --git a/currency.hpp b/currency.hpp
index a69383f..8c6c51e 100644
--- a/currency.hpp
+++ b/currency.hpp
@@ -25,7 +25,7 @@
 #include "config.hpp"
 
 #include "bourn_cast.hpp"
-#include "round_to.hpp"
+////#include "round_to.hpp"
 
 #include <cstdint>                      // int64_t
 #include <iostream>                     // ostream
@@ -44,22 +44,27 @@ using currency = double;
 #if defined USE_CURRENCY_CLASS
 class currency
 {
-//#if defined __GNUC__
-//#   pragma GCC diagnostic ignored "-Wuseless-cast"
-//#endif // defined __GNUC__
-//  using data_type = double;
+  #if defined __GNUC__
+  #   pragma GCC diagnostic ignored "-Wuseless-cast"
+  #endif // defined __GNUC__
+    using data_type = double;
 //  using data_type = long double;
-    using data_type = std::int64_t;
+//  using data_type = std::int64_t;
 
     friend std::ostream& operator<<(std::ostream&, currency const&);
     friend class currency_test;
 
   public:
+    static constexpr int cents_digits = 2;
+    static constexpr int cents_per_dollar = 100; // 10 ^ cents_digits
+
     currency() = default;
     currency(currency const&) = default;
     ~currency() = default;
 
     explicit currency(double d)  {m_ = from_double(d);}
+    // avoid troublesome overloads
+    explicit currency(std::int64_t d, bool) {m_ = bourn_cast<data_type>(d);} 
// instead: init-list
 
     currency& operator=(currency const&) = default;
     currency& operator=(double d) {m_ = from_double(d); return *this;}
@@ -106,6 +111,8 @@ class currency
 // Dangerous--can somehow take the place of operator*(double)
 //  currency const& operator*=(int z) {m_ *= z; return *this;}
 
+    data_type m() const {return m_;} // restrict to friends?
+
   private:
     // Want something just slightly more permissive:
 //  data_type from_double(double d) const {return bourn_cast<data_type>(100.0 
* d);}
@@ -114,17 +121,17 @@ class currency
     // ...and a bit insidious:
 //  data_type from_double(double d) const {return 
static_cast<data_type>(100.000000000001 * d);}
     // ...less bad:
-    data_type from_double(double d) const {return round(100.0 * d);}
-    double to_double() const {return bourn_cast<double>(m_) / 100.0;}
-//  data_type from_double(double d) const {return static_cast<data_type>(100.0 
* d);}
-//  double to_double() const {return static_cast<double>(m_) / 100.0;}
-
+//  data_type from_double(double d) const {return round(cents_per_dollar * d);}
+//  double to_double() const {return bourn_cast<double>(m_) / 
cents_per_dollar;}
+    data_type from_double(double d) const {return 
static_cast<data_type>(cents_per_dollar * d);}
+    double to_double() const {return static_cast<double>(m_) / 
cents_per_dollar;}
+#if 0 // will a fwd decl be wanted somewhere?
     data_type round(double d) const
         {
         static round_to<double> const r(0, r_to_nearest);
         return static_cast<data_type>(r(d));
         }
-
+#endif // 0
     data_type m_ = {0};
 };
 
diff --git a/death_benefits.cpp b/death_benefits.cpp
index ced6ac6..7d2a169 100644
--- a/death_benefits.cpp
+++ b/death_benefits.cpp
@@ -50,8 +50,8 @@ death_benefits::death_benefits
     for(int j = 0; j < length_; ++j)
         {
         dbopt_   [j] =                yi.DeathBenefitOption[j];
-        specamt_ [j] = round_specamt_(yi.SpecifiedAmount   [j]);
-        supplamt_[j] = round_specamt_(yi.SupplementalAmount[j]);
+        specamt_ [j] = round_specamt_.c(yi.SpecifiedAmount   [j]);
+        supplamt_[j] = round_specamt_.c(yi.SupplementalAmount[j]);
         }
 }
 
@@ -67,7 +67,7 @@ void death_benefits::set_specamt(currency z, int from_year, 
int to_year)
     LMI_ASSERT(                  to_year < length_);
     std::fill_n(specamt_.begin() + from_year, to_year - from_year, z);
 #endif // 0
-    z = round_specamt_(z);
+    z = round_specamt_.c(z);
     for(int j = from_year; j < std::min(length_, to_year); ++j)
         {
         specamt_[j] = z;
@@ -86,7 +86,7 @@ void death_benefits::set_supplamt(currency z, int from_year, 
int to_year)
     LMI_ASSERT(                  to_year < length_);
     std::fill_n(supplamt_.begin() + from_year, to_year - from_year, z);
 #endif // 0
-    z = round_specamt_(z);
+    z = round_specamt_.c(z);
     for(int j = from_year; j < std::min(length_, to_year); ++j)
         {
         supplamt_[j] = z;
diff --git a/outlay.cpp b/outlay.cpp
index 4e62ddb..c5fe894 100644
--- a/outlay.cpp
+++ b/outlay.cpp
@@ -37,15 +37,15 @@ modal_outlay::modal_outlay
     :round_gross_premium_  {round_gross_premium}
     ,round_withdrawal_     {round_withdrawal   }
     ,round_loan_           {round_loan         }
-    ,dumpin_               {            round_gross_premium_(yi.Dumpin)        
            }
-    ,external_1035_amount_ {            
round_gross_premium_(yi.External1035ExchangeAmount)}
-    ,internal_1035_amount_ {            
round_gross_premium_(yi.Internal1035ExchangeAmount)}
-    ,ee_modal_premiums_    {currencyize(round_gross_premium_(yi.Payment)       
           )}
-    ,ee_premium_modes_     {                                 yi.PaymentMode    
            }
-    ,er_modal_premiums_    
{currencyize(round_gross_premium_(yi.CorporationPayment)       )}
-    ,er_premium_modes_     {                                 
yi.CorporationPaymentMode     }
-    ,withdrawals_          {currencyize(round_withdrawal_   (yi.Withdrawal)    
           )}
-    ,new_cash_loans_       {currencyize(round_loan_         (yi.NewLoan)       
           )}
+    ,dumpin_               {round_gross_premium_(  yi.Dumpin)                  
  }
+    ,external_1035_amount_ {round_gross_premium_(  
yi.External1035ExchangeAmount)}
+    ,internal_1035_amount_ {round_gross_premium_(  
yi.Internal1035ExchangeAmount)}
+    ,ee_modal_premiums_    {round_gross_premium_.c(yi.Payment)                 
  }
+    ,ee_premium_modes_     {                       yi.PaymentMode              
  }
+    ,er_modal_premiums_    {round_gross_premium_.c(yi.CorporationPayment)      
  }
+    ,er_premium_modes_     {                       yi.CorporationPaymentMode   
  }
+    ,withdrawals_          {round_withdrawal_   .c(yi.Withdrawal)              
  }
+    ,new_cash_loans_       {round_loan_         .c(yi.NewLoan)                 
  }
 {
 }
 
diff --git a/round_to.hpp b/round_to.hpp
index 0996f6b..0419046 100644
--- a/round_to.hpp
+++ b/round_to.hpp
@@ -24,6 +24,7 @@
 
 #include "config.hpp"
 
+#include "currency.hpp"
 #include "mc_enum_type_enums.hpp"       // enum rounding_style
 #include "stl_extensions.hpp"           // nonstd::power()
 
@@ -266,6 +267,9 @@ class round_to
     RealType operator()(RealType r) const;
     std::vector<RealType> operator()(std::vector<RealType> r) const;
 
+    currency c(RealType r) const;
+    std::vector<currency> c(std::vector<RealType> r) const;
+
     int decimals() const;
     rounding_style style() const;
 
@@ -276,7 +280,9 @@ class round_to
     int decimals_                    {0};
     rounding_style style_            {r_indeterminate};
     max_prec_real scale_fwd_         {1.0};
+    max_prec_real scale_fwd_c_       {1.0};
     max_prec_real scale_back_        {1.0};
+    max_prec_real scale_back_c_      {1.0};
     rounding_fn_t rounding_function_ {detail::erroneous_rounding_function};
 };
 
@@ -309,7 +315,9 @@ round_to<RealType>::round_to(int decimals, rounding_style 
a_style)
     :decimals_          {decimals}
     ,style_             {a_style}
     ,scale_fwd_         {detail::perform_pow(max_prec_real(10.0), decimals)}
+    ,scale_fwd_c_       {detail::perform_pow(max_prec_real(10.0), decimals - 
currency::cents_digits)}
     ,scale_back_        {max_prec_real(1.0) / scale_fwd_}
+    ,scale_back_c_      {max_prec_real(1.0) / scale_fwd_c_}
     ,rounding_function_ {select_rounding_function(a_style)}
 {
 /*
@@ -370,6 +378,25 @@ inline std::vector<RealType> 
round_to<RealType>::operator()(std::vector<RealType
 }
 
 template<typename RealType>
+inline currency round_to<RealType>::c(RealType r) const
+{
+    RealType z = static_cast<RealType>
+        (rounding_function_(static_cast<RealType>(r * scale_fwd_)) * 
scale_back_c_
+        );
+    // include required headers
+    return currency(bourn_cast<std::int64_t>(z), true);
+}
+
+template<typename RealType>
+inline std::vector<currency> round_to<RealType>::c(std::vector<RealType> r) 
const
+{
+    std::vector<currency> z;
+    z.reserve(r.size());
+    for(auto const& i : r) {z.push_back(c(i));}
+    return z;
+}
+
+template<typename RealType>
 int round_to<RealType>::decimals() const
 {
     return decimals_;
diff --git a/round_to_test.cpp b/round_to_test.cpp
index 696a168..48aa675 100644
--- a/round_to_test.cpp
+++ b/round_to_test.cpp
@@ -544,6 +544,13 @@ int test_main(int, char*[])
     BOOST_TEST(2 == round1.decimals());
     BOOST_TEST(r_to_nearest == round1.style());
 
+    // Test rounding double to currency.
+    currency c = round0.c(1.61803398875);
+    BOOST_TEST((1.62 - c) < 1e-14);
+    BOOST_TEST_EQUAL(162, c.m());
+//  c *= 0.61803398875;
+//  BOOST_TEST_EQUAL(1, c);
+
     // Test a vector.
     std::vector<double> const v0 {3.1415926535, 2.718281828};
     std::vector<double> const v1 {round0(v0)};



reply via email to

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