lmi-commits
[Top][All Lists]
Advanced

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

[lmi-commits] [lmi] master 5e90841 2/4: Traffick in ints sooner than in


From: Greg Chicares
Subject: [lmi-commits] [lmi] master 5e90841 2/4: Traffick in ints sooner than in floats
Date: Thu, 15 Mar 2018 16:34:41 -0400 (EDT)

branch: master
commit 5e9084159a7bffd3adbcba7133c58a264939d59f
Author: Gregory W. Chicares <address@hidden>
Commit: Gregory W. Chicares <address@hidden>

    Traffick in ints sooner than in floats
    
    Where numeric values are to be scaled by 10^-6 for printing, store the
    scaling parameter as an integer like 6, not as a decimal like 0.000001,
    because the integer might be wanted later. Here, 6 is preferred to -6
    because the negation is implicit in the algorithm, but the |6| is data.
    
    int(6) can always be converted reliably to 10^6, and 10.0^6 is reliably
    integer-valued if nonstd::power() is used instead of a possibly flawed
    std::pow(). OTOH, 10.0^-6 can have no exact binary representation, and
    relying on even an optimal standard library to recover the exponent as
    an exact integer will someday end in tears--immediately in the happiest
    circumstance, or decades later, as in the present case.
    
    Subtleties:
     - To determine the proper scaling for a set of columns, std::min()
       was applied to 0.001 and 0.000001, where std::max() must be applied
       to 3 and 6, in order for uniform scaling to make them all fit.
     - There is no need to assert that the multiplier is nonzero, because
       no value of the integral exponent will make it so.
     - The default scaling parameter, formerly a multiplier of 1.0, becomes
       an exponent of 0, of course.
---
 ledger.cpp      |  8 +++---
 ledger_base.cpp | 83 +++++++++++++++++++++++----------------------------------
 ledger_base.hpp | 11 ++++----
 ledger_pdf.cpp  |  2 +-
 4 files changed, 44 insertions(+), 60 deletions(-)

diff --git a/ledger.cpp b/ledger.cpp
index a077b0b..c49f38d 100644
--- a/ledger.cpp
+++ b/ledger.cpp
@@ -315,19 +315,19 @@ int Ledger::GetMaxLength() const
 // largest absolute value of any number in any column of every subledger.
 void Ledger::AutoScale()
 {
-    double mult = ledger_invariant_->DetermineScaleFactor();
+    int k = ledger_invariant_->DetermineScalePower();
 
     ledger_map_t& l_map_rep = ledger_map_->held_;
     for(auto const& i : l_map_rep)
         {
-        mult = std::min(mult, i.second.DetermineScaleFactor());
+        k = std::max(k, i.second.DetermineScalePower());
         }
 
-    ledger_invariant_->ApplyScaleFactor(mult);
+    ledger_invariant_->ApplyScaleFactor(k);
 
     for(auto& i : l_map_rep)
         {
-        i.second.ApplyScaleFactor(mult);
+        i.second.ApplyScaleFactor(k);
         }
 }
 
diff --git a/ledger_base.cpp b/ledger_base.cpp
index 205413a..46ac4fe 100644
--- a/ledger_base.cpp
+++ b/ledger_base.cpp
@@ -27,24 +27,25 @@
 #include "assert_lmi.hpp"
 #include "crc32.hpp"
 #include "miscellany.hpp"               // minmax
+#include "stl_extensions.hpp"           // nonstd::power()
 #include "value_cast.hpp"
 
 #include <algorithm>                    // max(), min(), transform()
-#include <cmath>                        // floor(), log10(), pow()
+#include <cmath>                        // floor(), log10()
 #include <functional>                   // multiplies
 
 //============================================================================
 LedgerBase::LedgerBase(int a_Length)
-    :scale_factor_(1.0)
-    ,scale_unit_  ("")
+    :scale_power_(0)
+    ,scale_unit_ ("")
 {
     Initialize(a_Length);
 }
 
 //============================================================================
 LedgerBase::LedgerBase(LedgerBase const& obj)
-    :scale_factor_(obj.scale_factor_)
-    ,scale_unit_  (obj.scale_unit_)
+    :scale_power_(obj.scale_power_)
+    ,scale_unit_ (obj.scale_unit_)
 {
     Initialize(obj.GetLength());
     Copy(obj);
@@ -55,8 +56,8 @@ LedgerBase& LedgerBase::operator=(LedgerBase const& obj)
 {
     if(this != &obj)
         {
-        scale_factor_ = obj.scale_factor_;
-        scale_unit_   = obj.scale_unit_;
+        scale_power_ = obj.scale_power_;
+        scale_unit_  = obj.scale_unit_;
         Initialize(obj.GetLength());
         Copy(obj);
         }
@@ -103,7 +104,7 @@ void LedgerBase::Copy(LedgerBase const& obj)
     // Rather, their contents are information that is added in by derived
     // classes.
     //
-    // scale_factor_ and scale_unit_ aren't copied here because they're
+    // scale_power_ and scale_unit_ aren't copied here because they're
     // copied explicitly by the caller.
     //
     // TODO ?? There has to be a way to abstract this.
@@ -228,8 +229,7 @@ LedgerBase& LedgerBase::PlusEq
     ,std::vector<double> const& a_Inforce
     )
 {
-    LMI_ASSERT(0.0 != scale_factor_);
-    if(scale_factor_ != a_Addend.scale_factor_)
+    if(scale_power_ != a_Addend.scale_power_)
         {
         alarum() << "Cannot add differently scaled ledgers." << LMI_FLUSH;
         }
@@ -313,7 +313,7 @@ LedgerBase& LedgerBase::PlusEq
 // and make them variables.
 // PDF !! This seems not to be rigorously correct: $999,999,999.99 is
 // less than one billion, but rounds to $1,000,000,000.
-double LedgerBase::DetermineScaleFactor() const
+int LedgerBase::DetermineScalePower() const
 {
     double min_val = 0.0;
     double max_val = 0.0;
@@ -335,44 +335,27 @@ double LedgerBase::DetermineScaleFactor() const
 
     if(widest < 1000000000.0 || widest == 0)
         {
-        return 1.0;
+        return 0;
         }
+
     double d = std::log10(widest);
-    d = 3.0 * std::floor(d / 3.0);
-    d = std::pow(10.0, 6.0 - d);
+    d = std::floor(d / 3.0);
+    int k = 3 * static_cast<int>(d);
+    k = k - 6;
 
-    LMI_ASSERT(1.0E-18 <= d);
-    LMI_ASSERT(d <= 1.0);
+    LMI_ASSERT(0 <= k);
+    LMI_ASSERT(k <= 18);
 
-    return d;
+    return k;
 }
 
 namespace
 {
-    static std::string look_up_scale_unit(double a_ScalingFactor)
+    static std::string look_up_scale_unit(int decimal_power)
         {
-        if(0.0 == a_ScalingFactor)
-            {
-            alarum() << "Scaling factor is zero." << LMI_FLUSH;
-            return "ZERO";
-            }
-
-        double power = -std::log10(a_ScalingFactor);
-        // Assert absolute equality of two floating-point quantities, because
-        // they must both have integral values.
-        // PDF !! Suppress the assertion because, with MinGW-w64 gcc-7.2.0,
-        // it fails--apparently floor() gives the wrong answer, but trunc()
-        // and static_cast<int>() give the right answer for the test case
-        // described in the git commit message for 1c1bafa40. Obviously this
-        // needs further work because the behavior in other cases is unknown,
-        // and adding a small quantity to a near-integer to force it to round
-        // "correctly" is surely bogus.
-        // LMI_ASSERT(power == std::floor(power));
-        int z = static_cast<int>(0.1 + power);
-
         // US names are used; UK names are different.
         // Assume that numbers over 999 quintillion (US) will not be needed.
-        switch(z)
+        switch(decimal_power)
             {
             case 0:
                 {
@@ -411,7 +394,7 @@ namespace
                 //  break;
             default:
                 {
-                alarum() << "Case '" << z << "' not found." << LMI_FLUSH;
+                alarum() << "Case '" << decimal_power << "' not found." << 
LMI_FLUSH;
                 throw "Unreachable--silences a compiler diagnostic.";
                 }
             }
@@ -419,28 +402,27 @@ namespace
 } // Unnamed namespace.
 
 //============================================================================
-// Multiplies all scalable vectors by the factor from DetermineScaleFactor().
+// Multiplies all scalable vectors by the factor from DetermineScalePower().
 // Only columns are scaled, so we operate here only on vectors. A header
 // that shows e.g. face amount should show the true face amount, unscaled.
-void LedgerBase::ApplyScaleFactor(double a_Mult)
+void LedgerBase::ApplyScaleFactor(int decimal_power)
 {
-    LMI_ASSERT(0.0 != a_Mult);
-    LMI_ASSERT(0.0 != scale_factor_);
-    if(1.0 != scale_factor_)
+    if(0 != scale_power_)
         {
         alarum() << "Cannot scale the same ledger twice." << LMI_FLUSH;
         }
 
-    scale_factor_ = a_Mult;
-    if(1.0 == scale_factor_)
+    scale_power_ = decimal_power;
+    if(0 == scale_power_)
         {
         // Don't waste time multiplying all these vectors by one
         return;
         }
-    scale_unit_ = look_up_scale_unit(scale_factor_);
+
+    scale_unit_ = look_up_scale_unit(scale_power_);
 
     // ET !! *i.second *= M;
-    std::vector<double>M(GetLength(), scale_factor_);
+    std::vector<double>M(GetLength(), 1.0 / nonstd::power(10.0, scale_power_));
     for(auto& i : ScalableVectors)
         {
         std::vector<double>& v = *i.second;
@@ -461,9 +443,10 @@ std::string const& LedgerBase::ScaleUnit() const
 }
 
 //============================================================================
-double LedgerBase::ScaleFactor() const
+// PDF !! expunge
+int LedgerBase::ScalePower() const
 {
-    return scale_factor_;
+    return scale_power_;
 }
 
 //============================================================================
diff --git a/ledger_base.hpp b/ledger_base.hpp
index 70944f5..0c3902a 100644
--- a/ledger_base.hpp
+++ b/ledger_base.hpp
@@ -174,11 +174,12 @@ class LMI_SO LedgerBase
   public:
     virtual ~LedgerBase() = default;
 
-    void               ApplyScaleFactor(double a_Mult);
+    void               ApplyScaleFactor(int decimal_power);
 
-    double             DetermineScaleFactor() const;
+    int                DetermineScalePower() const;
     std::string const& ScaleUnit() const;
-    double             ScaleFactor() const;
+// PDF !! expunge
+    int                ScalePower() const;
     std::string        value_str(std::string const& map_key, int index) const;
     std::string        value_str(std::string const& map_key) const;
 
@@ -230,8 +231,8 @@ class LMI_SO LedgerBase
     string_map          Strings;
 
   private:
-    double              scale_factor_;
-    std::string         scale_unit_; // E.g. "thousands", "millions".
+    int                 scale_power_; // E.g., for (000,000): 6
+    std::string         scale_unit_;  // E.g., for (000,000): "millions"
 };
 
 template<typename T> void SpewVector
diff --git a/ledger_pdf.cpp b/ledger_pdf.cpp
index 850ac3b..d3eb99c 100644
--- a/ledger_pdf.cpp
+++ b/ledger_pdf.cpp
@@ -91,7 +91,7 @@ std::string write_ledger_as_pdf(Ledger const& ledger, 
fs::path const& filepath)
 
     Ledger scaled_ledger(ledger);
     // PDF !! Expunge this 'if' line (but not the statement it controls):
-    if(1.0 == scaled_ledger.GetLedgerInvariant().ScaleFactor())
+    if(0 == scaled_ledger.GetLedgerInvariant().ScalePower())
     scaled_ledger.AutoScale();
     auto const pdf = ledger_pdf_generator::create();
     pdf->write(scaled_ledger, pdf_out_file);



reply via email to

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