lmi-commits
[Top][All Lists]
Advanced

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

[lmi-commits] [lmi] valyuta/004 3ece0fc 3/4: For currency, round halfway


From: Greg Chicares
Subject: [lmi-commits] [lmi] valyuta/004 3ece0fc 3/4: For currency, round halfway cases to even
Date: Fri, 18 Dec 2020 07:29:53 -0500 (EST)

branch: valyuta/004
commit 3ece0fcc84971f7bcd0ceb171bd88ffaa9d040ba
Author: Gregory W. Chicares <gchicares@sbcglobal.net>
Commit: Gregory W. Chicares <gchicares@sbcglobal.net>

    For currency, round halfway cases to even
    
    The IEEE Standard for Floating-Point Arithmetic (IEEE 754) gives the
    rationale, which is basically to avoid bias.
    
    There is no performance cost: rounding away from even is not cheaper
    because it's not implemented in silicon.
    
    * ihs_basicval.cpp: The corridor-based specified-amount calculation
    rounds twice: once to convert a floating-point corridor factor like
    1.23 to an exact integer like 123, and again after multiplying that
    corridor factor by premium. Because the corridor factor is an exact
    integral percentage that needs to be recovered accurately from a
    floating-point representation, round() and nearbyint() are equally
    good; but it's insane to mix them even if it can be proven that no
    harm can come of it.
---
 Speed_gcc_i686-w64-mingw32 | 12 ++++++------
 currency.hpp               |  6 ++++--
 ihs_basicval.cpp           |  6 ++++--
 3 files changed, 14 insertions(+), 10 deletions(-)

diff --git a/Speed_gcc_i686-w64-mingw32 b/Speed_gcc_i686-w64-mingw32
index 96434ea..f28fcd2 100644
--- a/Speed_gcc_i686-w64-mingw32
+++ b/Speed_gcc_i686-w64-mingw32
@@ -1,7 +1,7 @@
 Test speed:
-  naic, no solve      : 6.500e-02 s mean;      64214 us least of  16 runs
-  naic, specamt solve : 1.158e-01 s mean;     113670 us least of   9 runs
-  naic, ee prem solve : 1.047e-01 s mean;     103533 us least of  10 runs
-  finra, no solve     : 2.501e-02 s mean;      23474 us least of  40 runs
-  finra, specamt solve: 6.883e-02 s mean;      67903 us least of  15 runs
-  finra, ee prem solve: 6.379e-02 s mean;      63007 us least of  16 runs
+  naic, no solve      : 6.467e-02 s mean;      64198 us least of  16 runs
+  naic, specamt solve : 1.134e-01 s mean;     113224 us least of   9 runs
+  naic, ee prem solve : 1.038e-01 s mean;     103612 us least of  10 runs
+  finra, no solve     : 2.448e-02 s mean;      23548 us least of  41 runs
+  finra, specamt solve: 6.828e-02 s mean;      68023 us least of  15 runs
+  finra, ee prem solve: 6.344e-02 s mean;      63140 us least of  16 runs
diff --git a/currency.hpp b/currency.hpp
index 1a0eaf8..00316b2 100644
--- a/currency.hpp
+++ b/currency.hpp
@@ -27,7 +27,8 @@
 #include "bourn_cast.hpp"
 ////#include "round_to.hpp"
 
-#include <cmath>                        // round
+#include <cfenv>                        // fesetround()
+#include <cmath>                        // nearbyint()
 #include <cstdint>                      // int64_t
 #include <iostream>                     // ostream
 #include <vector>
@@ -161,7 +162,8 @@ class currency
     data_type round(double d) const
         {
 #if !defined MAKE_IT_FASTER
-        return bourn_cast<data_type>(std::round(d));
+        std::fesetround(FE_TONEAREST);
+        return bourn_cast<data_type>(std::nearbyint(d));
 #else  // defined MAKE_IT_FASTER
         static_assert(std::is_floating_point<data_type>::value);
         return d;
diff --git a/ihs_basicval.cpp b/ihs_basicval.cpp
index ae2b5c6..4ac3199 100644
--- a/ihs_basicval.cpp
+++ b/ihs_basicval.cpp
@@ -55,7 +55,8 @@
 #include "value_cast.hpp"
 
 #include <algorithm>
-#include <cmath>                        // pow()
+#include <cfenv>                        // fesetround()
+#include <cmath>                        // nearbyint(), pow()
 #include <functional>                   // multiplies
 #include <limits>
 #include <numeric>
@@ -1568,7 +1569,8 @@ currency BasicValues::GetModalSpecAmtCorridor(currency 
annualized_pmt) const
 {
     int const k = round_corridor_factor().decimals();
     double const s = nonstd::power(10, k);
-    double const z = std::round(s * GetCorridorFactor()[0]);
+    std::fesetround(FE_TONEAREST);
+    double const z = std::nearbyint(s * GetCorridorFactor()[0]);
     return round_min_specamt().c((z * annualized_pmt) / s);
 }
 



reply via email to

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