$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
Subject: [Boost-commit] svn:boost r74049 - in sandbox/e_float: boost/e_float libs/e_float/src/e_float/efx libs/e_float/src/e_float/gmp libs/e_float/src/e_float/mpfr libs/e_float/test/real/cases
From: e_float_at_[hidden]
Date: 2011-08-24 17:09:02
Author: christopher_kormanyos
Date: 2011-08-24 17:08:59 EDT (Wed, 24 Aug 2011)
New Revision: 74049
URL: http://svn.boost.org/trac/boost/changeset/74049
Log:
- Corrected various standardization issues such as comparison of min with zero, comparisons of NaN's and positive and negative infinities.
- Added several relevant test cases thereof.
Text files modified: 
   sandbox/e_float/boost/e_float/e_float_gmp.hpp                                       |    15 ++---                                   
   sandbox/e_float/boost/e_float/e_float_mpfr.hpp                                      |     4                                         
   sandbox/e_float/libs/e_float/src/e_float/efx/e_float_efx.cpp                        |    69 +++++++++++++++++++++-------            
   sandbox/e_float/libs/e_float/src/e_float/gmp/e_float_gmp.cpp                        |    94 ++++++++++++++++++++++++++++----------- 
   sandbox/e_float/libs/e_float/src/e_float/mpfr/e_float_mpfr.cpp                      |    47 +++++++++++++++++++                     
   sandbox/e_float/libs/e_float/test/real/cases/test_case_0000x_overflow_underflow.cpp |     4 +                                       
   sandbox/e_float/libs/e_float/test/real/cases/test_case_0000y_write_to_ostream.cpp   |    25 ++++++++++                              
   sandbox/e_float/libs/e_float/test/real/cases/test_case_0000z_global_ops_pod.cpp     |    32 ++++++++++++                            
   8 files changed, 228 insertions(+), 62 deletions(-)
Modified: sandbox/e_float/boost/e_float/e_float_gmp.hpp
==============================================================================
--- sandbox/e_float/boost/e_float/e_float_gmp.hpp	(original)
+++ sandbox/e_float/boost/e_float/e_float_gmp.hpp	2011-08-24 17:08:59 EDT (Wed, 24 Aug 2011)
@@ -61,8 +61,8 @@
       static const INT32 ef_digits    = static_cast<INT32>((static_cast<signed long long>(ef_digits10) * 2136LL) / 643LL);
       static const INT32 ef_radix     = static_cast<INT32>(2);
 
-      static const INT64 ef_max_exp   = static_cast<INT64>(LONG_MAX - 8LL); // TBD: Ensure INT64 >= long
-      static const INT64 ef_min_exp   = static_cast<INT64>(LONG_MIN + 8LL); // TBD: Ensure INT64 >= long
+      static const INT64 ef_max_exp   = static_cast<INT64>(LONG_MAX - 31LL); // TBD: Ensure that (INT64 >= long)
+      static const INT64 ef_min_exp   = static_cast<INT64>(LONG_MIN + 31LL); // TBD: Ensure that (INT64 >= long)
       static const INT64 ef_max_exp10 = static_cast<INT64>((static_cast<signed long long>(ef_max_exp) * 643LL) / 2136LL);
       static const INT64 ef_min_exp10 = static_cast<INT64>((static_cast<signed long long>(ef_min_exp) * 643LL) / 2136LL);
 
@@ -72,7 +72,8 @@
       typedef enum enum_fpclass
       {
         ef_finite,
-        ef_inf,
+        ef_inf_pos,
+        ef_inf_neg,
         ef_NaN
       }
       t_fpclass;
@@ -136,9 +137,9 @@
       virtual e_float& negate(void);
 
       // Comparison functions
-      virtual bool isnan   (void) const { return (fpclass == ef_NaN); }
-      virtual bool isinf   (void) const { return (fpclass == ef_inf); }
-      virtual bool isfinite(void) const { return (fpclass == ef_finite); }
+      virtual bool isnan   (void) const { return  (fpclass == ef_NaN); }
+      virtual bool isinf   (void) const { return ((fpclass == ef_inf_pos) || (fpclass == ef_inf_neg)); }
+      virtual bool isfinite(void) const { return  (fpclass == ef_finite); }
 
       virtual bool iszero (void) const;
       virtual bool isone  (void) const;
@@ -164,8 +165,6 @@
 
       static void init(void);
 
-      INT32 cmp_data(const ::mpf_t& v) const;
-
       void from_unsigned_long_long(const unsigned long long u);
       void from_unsigned_long(const unsigned long u);
 
Modified: sandbox/e_float/boost/e_float/e_float_mpfr.hpp
==============================================================================
--- sandbox/e_float/boost/e_float/e_float_mpfr.hpp	(original)
+++ sandbox/e_float/boost/e_float/e_float_mpfr.hpp	2011-08-24 17:08:59 EDT (Wed, 24 Aug 2011)
@@ -69,8 +69,8 @@
       static const INT32 ef_digits    = static_cast<INT32>((static_cast<signed long long>(ef_digits10) * 2136LL) / 643LL);
       static const INT32 ef_radix     = 2;
 
-      static const INT64 ef_max_exp   = static_cast<INT64>(LONG_MAX / static_cast<signed long>(2L)); // TBD: Ensure INT64 >= long
-      static const INT64 ef_min_exp   = static_cast<INT64>(LONG_MIN / static_cast<signed long>(2L)); // TBD: Ensure INT64 >= long
+      static const INT64 ef_max_exp   = static_cast<INT64>(LONG_MAX / static_cast<signed long>(2L)); // TBD: Ensure that (INT64 >= long)
+      static const INT64 ef_min_exp   = static_cast<INT64>(LONG_MIN / static_cast<signed long>(2L)); // TBD: Ensure that (INT64 >= long)
       static const INT64 ef_max_exp10 = static_cast<INT64>((static_cast<signed long long>(ef_max_exp) * 643LL) / 2136LL);
       static const INT64 ef_min_exp10 = static_cast<INT64>((static_cast<signed long long>(ef_min_exp) * 643LL) / 2136LL);
 
Modified: sandbox/e_float/libs/e_float/src/e_float/efx/e_float_efx.cpp
==============================================================================
--- sandbox/e_float/libs/e_float/src/e_float/efx/e_float_efx.cpp	(original)
+++ sandbox/e_float/libs/e_float/src/e_float/efx/e_float_efx.cpp	2011-08-24 17:08:59 EDT (Wed, 24 Aug 2011)
@@ -1106,6 +1106,38 @@
   //                 0 for *this = v
   //                -1 for *this < v
 
+  // Handle all non-finite cases.
+  if((!isfinite()) || (!v.isfinite()))
+  {
+    // NaN can never equal NaN. Return an implementation-dependent
+    // signed result. Also note that comparison of NaN with NaN
+    // using operators greater-than or less-than is undefined.
+    if(isnan() || v.isnan()) { return (isnan() ? static_cast<INT32>(1) : static_cast<INT32>(-1)); }
+
+    if(isinf() && v.isinf())
+    {
+      // Both *this and v are infinite. They are equal if they have the same sign.
+      // Otherwise, *this is less than v if and only if *this is negative.
+      return ((neg == v.neg) ? static_cast<INT32>(0) : (neg ? static_cast<INT32>(-1) : static_cast<INT32>(1)));
+    }
+
+    if(isinf())
+    {
+      // *this is infinite, but v is finite.
+      // So negative infinite *this is less than any finite v.
+      // Whereas positive infinite *this is greater than any finite v.
+      return (isneg() ? static_cast<INT32>(-1) : static_cast<INT32>(1));
+    }
+    else
+    {
+      // *this is finite, and v is infinite.
+      // So any finite *this is greater than negative infinite v.
+      // Whereas any finite *this is less than positive infinite v.
+      return (v.neg ? static_cast<INT32>(1) : static_cast<INT32>(-1));
+    }
+  }
+
+  // And now handle all *finite* cases.
   if(iszero())
   {
     // The value of *this is zero and v is either zero or non-zero.
@@ -1146,21 +1178,7 @@
 
 bool efx::e_float::iszero(void) const
 {
-  if(fpclass == ef_finite)
-  {
-    if(exp < static_cast<INT64>(std::numeric_limits<e_float>::min_exponent10))
-    {
-      return true;
-    }
-    else
-    {
-      return (data[0u] == static_cast<UINT32>(0u));
-    }
-  }
-  else
-  {
-    return false;
-  }
+  return ((fpclass == ef_finite) && (data[0u] == static_cast<UINT32>(0u)));
 }
 
 bool efx::e_float::isone(void) const
@@ -1543,7 +1561,7 @@
 
 INT64 efx::e_float::get_order_fast(void) const
 {
-  if(iszero())
+  if((!isfinite()) || (data[0] == static_cast<UINT32>(0u)))
   {
     return static_cast<INT64>(0);
   }
@@ -1830,9 +1848,24 @@
   }
 
   // ...and check for underflow.
-  if(exp < std::numeric_limits<e_float>::min_exponent10)
+  if(exp <= std::numeric_limits<e_float>::min_exponent10)
   {
-    *this = ef::zero();
+    if(exp == std::numeric_limits<e_float>::min_exponent10)
+    {
+      // Check for identity with the minimum value.
+      e_float test = *this;
+
+      test.exp = static_cast<INT64>(0);
+
+      if(test.isone())
+      {
+        *this = ef::zero();
+      }
+    }
+    else
+    {
+      *this = ef::zero();
+    }
   }
 
   return true;
Modified: sandbox/e_float/libs/e_float/src/e_float/gmp/e_float_gmp.cpp
==============================================================================
--- sandbox/e_float/libs/e_float/src/e_float/gmp/e_float_gmp.cpp	(original)
+++ sandbox/e_float/libs/e_float/src/e_float/gmp/e_float_gmp.cpp	2011-08-24 17:08:59 EDT (Wed, 24 Aug 2011)
@@ -398,7 +398,7 @@
 
   if(b_u_is_inf || b_v_is_inf)
   {
-    const bool b_result_is_neg = (isneg() == v.isneg());
+    const bool b_result_is_neg = (isneg() != v.isneg());
 
     *this = ((!b_result_is_neg) ?  std::numeric_limits<e_float>::infinity()
                                 : -std::numeric_limits<e_float>::infinity());
@@ -433,7 +433,7 @@
       }
       else
       {
-        const bool b_result_is_neg = (isneg() == v.isneg());
+        const bool b_result_is_neg = (isneg() != v.isneg());
 
         *this = ((!b_result_is_neg) ?  std::numeric_limits<e_float>::infinity()
                                     : -std::numeric_limits<e_float>::infinity());
@@ -637,42 +637,57 @@
   return *this;
 }
 
-INT32 gmp::e_float::cmp_data(const ::mpf_t& v) const
+INT32 gmp::e_float::cmp(const e_float& v) const
 {
-  const INT32 result = static_cast<INT32>(::mpf_cmp(rop, v));
-  
-  if(result > static_cast<INT32>(0))
-  {
-    return static_cast<INT32>(1);
-  }
-  else if(result < static_cast<INT32>(0))
-  {
-    return static_cast<INT32>(-1);
-  }
-  else
+  // Handle all non-finite cases.
+  if((!isfinite()) || (!v.isfinite()))
   {
-    return static_cast<INT32>(0);
-  }
-}
+    // NaN can never equal NaN. Return an implementation-dependent
+    // signed result. Also note that comparison of NaN with NaN
+    // using operators greater-than or less-than is undefined.
+    if(isnan() || v.isnan()) { return (isnan() ? static_cast<INT32>(1) : static_cast<INT32>(-1)); }
 
-INT32 gmp::e_float::cmp(const e_float& v) const
-{
-  const INT32 result = cmp_data(v.rop);
+    if(isinf() && v.isinf())
+    {
+      // Both *this and v are infinite. They are equal if they have the same sign.
+      // Otherwise, *this is less than v if and only if *this is negative.
+      return ((isneg() == v.isneg()) ? static_cast<INT32>(0) : (isneg() ? static_cast<INT32>(-1) : static_cast<INT32>(1)));
+    }
+
+    if(isinf())
+    {
+      // *this is infinite, but v is finite.
+      // So negative infinite *this is less than any finite v.
+      // Whereas positive infinite *this is greater than any finite v.
+      return (isneg() ? static_cast<INT32>(-1) : static_cast<INT32>(1));
+    }
+    else
+    {
+      // *this is finite, and v is infinite.
+      // So any finite *this is greater than negative infinite v.
+      // Whereas any finite *this is less than positive infinite v.
+      return (v.isneg() ? static_cast<INT32>(1) : static_cast<INT32>(-1));
+    }
+  }
 
-  if(result == static_cast<INT32>(0))
+  // And now handle all *finite* cases.
+  if(iszero() && v.iszero())
   {
-    return ((isfinite() && v.isfinite()) ? static_cast<INT32>(0) : static_cast<INT32>(1));
+    return static_cast<INT32>(0);
   }
   else
   {
-    return result;
+    const int result = ::mpf_cmp(rop, v.rop);
+  
+    if     (result > 0) { return static_cast<INT32>(1); }
+    else if(result < 0) { return static_cast<INT32>(-1); }
+    else { return static_cast<INT32>(0); }
   }
 }
 
 bool gmp::e_float::iszero(void) const
 {
-  // Check if the value of *this is identically 0 or very close to 0.
-  return isint() && (cmp(ef::zero()) == static_cast<INT32>(0));
+  return (::mpf_sgn(rop) == 0);
 }
 
 bool gmp::e_float::isone(void) const
@@ -689,7 +704,14 @@
 
 bool gmp::e_float::isneg(void) const
 {
-  return (::mpf_sgn(rop) < 0);
+  if(isinf())
+  {
+    return (fpclass == ef_inf_neg);
+  }
+  else
+  {
+    return (::mpf_sgn(rop) < 0);
+  }
 }
 
 const gmp::e_float& gmp::e_float::my_value_nan(void) const
@@ -703,12 +725,28 @@
 const gmp::e_float& gmp::e_float::my_value_inf(void) const
 {
   static e_float val(0u);
-  val.fpclass = ef_inf;
+  val.fpclass = ef_inf_pos;
   static const e_float inf(val);
   return inf;
 }
 
-e_float& gmp::e_float::negate(void) { ::mpf_neg(rop, rop); return *this; }
+e_float& gmp::e_float::negate(void)
+{
+  if(fpclass == ef_inf_pos)
+  {
+    fpclass = ef_inf_neg;
+  }
+  else if(fpclass == ef_inf_neg)
+  {
+    fpclass = ef_inf_pos;
+  }
+  else
+  {
+    ::mpf_neg(rop, rop);
+  }
+
+  return *this;
+}
 
 e_float& gmp::e_float::operator++(void) { ::mpf_add_ui(rop, rop, static_cast<unsigned long>(1u)); return *this; }
 e_float& gmp::e_float::operator--(void) { ::mpf_sub_ui(rop, rop, static_cast<unsigned long>(1u)); return *this; }
Modified: sandbox/e_float/libs/e_float/src/e_float/mpfr/e_float_mpfr.cpp
==============================================================================
--- sandbox/e_float/libs/e_float/src/e_float/mpfr/e_float_mpfr.cpp	(original)
+++ sandbox/e_float/libs/e_float/src/e_float/mpfr/e_float_mpfr.cpp	2011-08-24 17:08:59 EDT (Wed, 24 Aug 2011)
@@ -254,7 +254,46 @@
 
 INT32 mpfr::e_float::cmp(const e_float& v) const
 {
-  return static_cast<INT32>(::mpfr_cmp(rop, v.rop));
+  // Handle all non-finite cases.
+  if((!isfinite()) || (!v.isfinite()))
+  {
+    // NaN can never equal NaN. Return an implementation-dependent
+    // signed result. Also note that comparison of NaN with NaN
+    // using operators greater-than or less-than is undefined.
+    if(isnan() || v.isnan()) { return (isnan() ? static_cast<INT32>(1) : static_cast<INT32>(-1)); }
+
+    if(isinf() && v.isinf())
+    {
+      // Both *this and v are infinite. They are equal if they have the same sign.
+      // Otherwise, *this is less than v if and only if *this is negative.
+      return ((isneg() == v.isneg()) ? static_cast<INT32>(0) : (isneg() ? static_cast<INT32>(-1) : static_cast<INT32>(1)));
+    }
+
+    if(isinf())
+    {
+      // *this is infinite, but v is finite.
+      // So negative infinite *this is less than any finite v.
+      // Whereas positive infinite *this is greater than any finite v.
+      return (isneg() ? static_cast<INT32>(-1) : static_cast<INT32>(1));
+    }
+    else
+    {
+      // *this is finite, and v is infinite.
+      // So any finite *this is greater than negative infinite v.
+      // Whereas any finite *this is less than positive infinite v.
+      return (v.isneg() ? static_cast<INT32>(1) : static_cast<INT32>(-1));
+    }
+  }
+
+  // And now handle all *finite* cases.
+  if(iszero() && v.iszero())
+  {
+    return static_cast<INT32>(0);
+  }
+  else
+  {
+    return static_cast<INT32>(::mpfr_cmp(rop, v.rop));
+  }
 }
 
 mpfr::e_float& mpfr::e_float::calculate_sqrt(void)
@@ -272,11 +311,15 @@
 bool mpfr::e_float::isnan   (void) const { return  (::mpfr_nan_p    (rop)  != 0); }
 bool mpfr::e_float::isinf   (void) const { return  (::mpfr_inf_p    (rop)  != 0); }
 bool mpfr::e_float::isfinite(void) const { return  ((!isnan()) && (!isinf())); }
-bool mpfr::e_float::iszero  (void) const { return  (::mpfr_zero_p   (rop)  != 0); }
 bool mpfr::e_float::isone   (void) const { return ((::mpfr_integer_p(rop)  != 0) && (::mpfr_get_si(rop, GMP_RNDN) == static_cast<unsigned long>(1uL))); }
 bool mpfr::e_float::isint   (void) const { return  (::mpfr_integer_p(rop)  != 0); }
 bool mpfr::e_float::isneg   (void) const { return  (::mpfr_sgn      (rop)  <  0); }
 
+bool mpfr::e_float::iszero(void) const
+{
+  return (::mpfr_zero_p(rop) != 0);
+}
+
 mpfr::e_float& mpfr::e_float::operator++(void) { ::mpfr_add_ui(rop, rop, static_cast<unsigned long>(1uL), GMP_RNDN); return *this; }
 mpfr::e_float& mpfr::e_float::operator--(void) { ::mpfr_sub_ui(rop, rop, static_cast<unsigned long>(1uL), GMP_RNDN); return *this; }
 
Modified: sandbox/e_float/libs/e_float/test/real/cases/test_case_0000x_overflow_underflow.cpp
==============================================================================
--- sandbox/e_float/libs/e_float/test/real/cases/test_case_0000x_overflow_underflow.cpp	(original)
+++ sandbox/e_float/libs/e_float/test/real/cases/test_case_0000x_overflow_underflow.cpp	2011-08-24 17:08:59 EDT (Wed, 24 Aug 2011)
@@ -198,7 +198,9 @@
 
           data.push_back(y);
 
-          if(ef::iszero(y)) { break; }
+          const bool is_zero_or_lt_min = (ef::iszero(y) || (y < (std::numeric_limits<e_float>::min)()));
+
+          if(is_zero_or_lt_min) { break; }
         }
 
         my_test_result = (k > static_cast<INT32>(1)) && (k < kmax);
Modified: sandbox/e_float/libs/e_float/test/real/cases/test_case_0000y_write_to_ostream.cpp
==============================================================================
--- sandbox/e_float/libs/e_float/test/real/cases/test_case_0000y_write_to_ostream.cpp	(original)
+++ sandbox/e_float/libs/e_float/test/real/cases/test_case_0000y_write_to_ostream.cpp	2011-08-24 17:08:59 EDT (Wed, 24 Aug 2011)
@@ -346,6 +346,20 @@
         std::string str;
         std::stringstream ss;
 
+        ss << ef::zero();
+        str = ss.str();
+        data.push_back(e_float(str));
+        my_test_result &= (str == std::string("0"));
+        ss.clear();
+        ss.str("");
+
+        ss << ef::one_minus();
+        str = ss.str();
+        data.push_back(e_float(str));
+        my_test_result &= (str == std::string("-1"));
+        ss.clear();
+        ss.str("");
+
         ss << ef::ten();
         str = ss.str();
         data.push_back(e_float(str));
@@ -433,7 +447,16 @@
         ss << std::showpoint << ef::eight();
         str = ss.str();
         data.push_back(e_float(str));
-        my_test_result &= (str == std::string("8.00000"));
+        static const std::string str_8_point_zeros =   std::string("8.")
+                                                     + std::string(static_cast<std::size_t>(default_prec() - 1u), static_cast<char>('0'));
+        my_test_result &= (str == str_8_point_zeros);
+        ss.clear();
+        ss.str("");
+
+        ss << std::showpoint << -ef::eight();
+        str = ss.str();
+        data.push_back(e_float(str));
+        my_test_result &= (str == ("-" + str_8_point_zeros));
         ss.clear();
         ss.str("");
 
Modified: sandbox/e_float/libs/e_float/test/real/cases/test_case_0000z_global_ops_pod.cpp
==============================================================================
--- sandbox/e_float/libs/e_float/test/real/cases/test_case_0000z_global_ops_pod.cpp	(original)
+++ sandbox/e_float/libs/e_float/test/real/cases/test_case_0000z_global_ops_pod.cpp	2011-08-24 17:08:59 EDT (Wed, 24 Aug 2011)
@@ -16,6 +16,7 @@
 #include <boost/e_float/e_float.hpp>
 #include <boost/e_float/e_float_functions.hpp>
 #include "../test_case_real.h"
+#include "../../../src/utility/util_lexical_cast.h"
 
 namespace
 {
@@ -203,8 +204,20 @@
         my_test_result &= ((ef::one() * 4.0) == 4);
         my_test_result &= ((4.0 * ef::one()) == 4);
 
-        const e_float huge("1e12345678");
-        const e_float tiny("1e-12345678");
+        my_test_result &= (std::numeric_limits<e_float>::quiet_NaN() != 0);
+        my_test_result &= (std::numeric_limits<e_float>::quiet_NaN() != ef::one());
+        my_test_result &= (std::numeric_limits<e_float>::quiet_NaN() != std::numeric_limits<e_float>::quiet_NaN());
+
+        static const e_float huge("1e12345678");
+        static const e_float tiny("1e-12345678");
+
+        my_test_result &= (huge < +std::numeric_limits<e_float>::infinity());
+        my_test_result &= (tiny > -std::numeric_limits<e_float>::infinity());
+        my_test_result &= (+std::numeric_limits<e_float>::infinity() == (+1 / ef::zero()));
+        my_test_result &= (-std::numeric_limits<e_float>::infinity() == (-1 / ef::zero()));
+        my_test_result &= (-std::numeric_limits<e_float>::infinity() != +std::numeric_limits<e_float>::infinity());
+        my_test_result &= (+std::numeric_limits<e_float>::infinity() >  -std::numeric_limits<e_float>::infinity());
+        my_test_result &= (-std::numeric_limits<e_float>::infinity() <  +std::numeric_limits<e_float>::infinity());
 
         float f = huge;
         double d = huge;
@@ -221,6 +234,21 @@
         my_test_result &= (f == 0.0f);
         my_test_result &= (d == 0.0);
         my_test_result &= (ld == static_cast<long double>(0.0));
+
+        static const e_float min_value("1e" + Util::lexical_cast(std::numeric_limits<e_float>::min_exponent10));
+
+        my_test_result &= ((std::numeric_limits<e_float>::min)() == min_value);
+        my_test_result &= ((std::numeric_limits<e_float>::min)() != 0);
+        my_test_result &= ((std::numeric_limits<e_float>::min)() != ef::zero());
+        my_test_result &= (0 != (std::numeric_limits<e_float>::min)());
+        my_test_result &= (ef::zero() != (std::numeric_limits<e_float>::min)());
+        my_test_result &= (0 < +(std::numeric_limits<e_float>::min)());
+        my_test_result &= (0 > -(std::numeric_limits<e_float>::min)());
+
+        static const e_float a_little_more_than_min_value("1e" + Util::lexical_cast(std::numeric_limits<e_float>::min_exponent10 + static_cast<INT64>(1)));
+
+        my_test_result &= (a_little_more_than_min_value != 0);
+        my_test_result &= (a_little_more_than_min_value > (std::numeric_limits<e_float>::min)());
       }
     };