Boost logo

Boost-Commit :

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


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk