lmi-commits
[Top][All Lists]
Advanced

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

[lmi-commits] [lmi] master eab8e30 4/6: Improve signum()


From: Greg Chicares
Subject: [lmi-commits] [lmi] master eab8e30 4/6: Improve signum()
Date: Sun, 30 Apr 2017 11:49:36 -0400 (EDT)

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

    Improve signum()
    
    Notably, C++11 makes it possible to examine the sign of a NaN portably.
---
 tn_range.tpp      | 38 ++++++++------------------------------
 tn_range_test.cpp |  4 ++--
 2 files changed, 10 insertions(+), 32 deletions(-)

diff --git a/tn_range.tpp b/tn_range.tpp
index 4d29e56..50954d5 100644
--- a/tn_range.tpp
+++ b/tn_range.tpp
@@ -24,7 +24,7 @@
 #include "alert.hpp"
 #include "value_cast.hpp"
 
-#include <cmath>                        // std::pow()
+#include <cmath>                        // std::pow(), std::signbit()
 #include <exception>
 #include <istream>
 #include <limits>
@@ -99,29 +99,17 @@ namespace
         return strictly_between_extrema_tester<T>()(t);
     }
 
-    /// Signum, defined here to return 0 for NaNs.
+    /// Algebraic sign of argument.
     ///
-    /// To handle unsigned types without warnings, the value zero is
-    /// stored in a volatile variable, and the value negative one is
-    /// cast to the argument type.
+    /// Return value is of same type as argument, as for many members
+    /// of std::numeric_limits. Thus, (t * signum(t)) is of type T,
+    /// which would not always be the case if an int were returned.
 
     template<typename T>
     T signum(T t)
     {
         static_assert(std::is_arithmetic<T>::value, "");
-        T volatile zero = 0;
-        if(t < zero)
-            {
-            return static_cast<T>(-1);
-            }
-        else if(0 < t)
-            {
-            return 1;
-            }
-        else
-            {
-            return 0;
-            }
+        return (0 == t) ? 0 : std::signbit(t) ? -1 : 1;
     }
 
     /// Exact-integer determination for floating types.
@@ -236,23 +224,13 @@ namespace
             {
             return t;
             }
-
-        // The return values computed here are cast to T because, for
-        // instance, if T is signed char, then an integral promotion
-        // would be performed--even though these calculations are
-        // actually reachable only for floating-point types. This
-        // workaround is more compact than specializing the template.
         else if(t < direction)
             {
-            return static_cast<T>
-                (t * (1 + signum(t) * std::numeric_limits<T>::epsilon())
-                );
+            return t * (T(1) + signum(t) * std::numeric_limits<T>::epsilon());
             }
         else if(direction < t)
             {
-            return static_cast<T>
-                (t * (1 - signum(t) * std::numeric_limits<T>::epsilon())
-                );
+            return t * (T(1) - signum(t) * std::numeric_limits<T>::epsilon());
             }
         else
             {
diff --git a/tn_range_test.cpp b/tn_range_test.cpp
index 5ab39ab..c4e85ea 100644
--- a/tn_range_test.cpp
+++ b/tn_range_test.cpp
@@ -171,8 +171,8 @@ void tn_range_test::test_auxiliary_functions(char const* 
file, int line)
     if(is_iec559 && has_quiet_NaN)
         {
         T const qnanT = std::numeric_limits<T>::quiet_NaN();
-        INVOKE_BOOST_TEST_EQUAL( 0, signum(-qnanT), file, line);
-        INVOKE_BOOST_TEST_EQUAL( 0, signum( qnanT), file, line);
+        INVOKE_BOOST_TEST_EQUAL(-1, signum(-qnanT), file, line);
+        INVOKE_BOOST_TEST_EQUAL( 1, signum( qnanT), file, line);
         }
 }
 



reply via email to

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