[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);
}