This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [Patch] libstdc++/21193 (float, double, long double)


Paolo Carlini wrote:

>Tested x86-linux and, lightly, x86-64-linux.
>  
>
After a lot of testing, both on x86 and x86-64, the final version below
is what I'm going to commit: the specialization for long double scales
better to 64-bit and is much more understandable, in my opinion.

Paolo.

///////////

Index: functional
===================================================================
RCS file: /cvs/gcc/gcc/libstdc++-v3/include/tr1/functional,v
retrieving revision 1.12
diff -u -r1.12 functional
--- functional	13 Jul 2005 10:47:40 -0000	1.12
+++ functional	14 Jul 2005 16:43:46 -0000
@@ -40,6 +40,7 @@
 #include <bits/cpp_type_traits.h>
 #include <string>               // for std::tr1::hash
 #include <cstdlib>              // for std::abort
+#include <cmath>                // for std::frexp
 #include <tr1/tuple>
 
 namespace std
@@ -1116,10 +1117,6 @@
   tr1_hashtable_define_trivial_hash(unsigned int);
   tr1_hashtable_define_trivial_hash(unsigned long);
 
-  tr1_hashtable_define_trivial_hash(float);
-  tr1_hashtable_define_trivial_hash(double);
-  tr1_hashtable_define_trivial_hash(long double);
-
 #undef tr1_hashtable_define_trivial_hash
 
   template<typename T>
@@ -1133,7 +1130,7 @@
   // Fowler / Noll / Vo (FNV) Hash (type FNV-1a)
   // (used by the next specializations of std::tr1::hash<>)
 
-  // Dummy generic implementation (for sizeof(size_t) != 4,8).
+  // Dummy generic implementation (for sizeof(size_t) != 4, 8).
   template<std::size_t = sizeof(std::size_t)>
     struct Fnv_hash
     {
@@ -1179,9 +1176,9 @@
       }
     };
 
-  // XXX String hash probably shouldn't be an inline member function,
-  // since it's nontrivial.  Once we have the framework for TR1 .cc
-  // files, this should go in one.
+  // XXX String and floating point hashes probably shouldn't be inline
+  // member functions, since are nontrivial.  Once we have the framework
+  // for TR1 .cc files, these should go in one.
   template<>
     struct hash<std::string>
     {
@@ -1203,6 +1200,69 @@
     };
 #endif
 
+  template<>
+    struct hash<float>
+    {
+      std::size_t
+      operator()(float fval) const
+      {
+	std::size_t result = 0;
+
+	// 0 and -0 both hash to zero.
+	if (fval != 0.0f)
+	  result = Fnv_hash<>::hash(reinterpret_cast<const char*>(&fval),
+				    sizeof(fval));
+	return result;
+      }
+    };
+
+  template<>
+    struct hash<double>
+    {
+      std::size_t
+      operator()(double dval) const
+      {
+	std::size_t result = 0;
+
+	// 0 and -0 both hash to zero.
+	if (dval != 0.0)
+	  result = Fnv_hash<>::hash(reinterpret_cast<const char*>(&dval),
+				    sizeof(dval));
+	return result;
+      }
+    };
+
+  // For long double, careful with random padding bits (e.g., on x86,
+  // 10 bytes -> 12 bytes) and resort to frexp.
+  template<>
+    struct hash<long double>
+    {
+      std::size_t
+      operator()(long double ldval) const
+      {
+	std::size_t result = 0;
+
+	int exponent;
+	ldval = std::frexp(ldval, &exponent);
+	ldval < 0.0l ? ldval += 1.0l : ldval;
+
+	const long double mult = std::numeric_limits<std::size_t>::max() + 1.0l;
+	ldval *= mult;
+
+	// Try to use all the bits of the mantissa (really necessary only
+	// on 32-bit targets, at least for 80-bit floating point formats).
+	const std::size_t hibits = (std::size_t)ldval;
+	ldval = (ldval - (long double)hibits) * mult;
+
+	const std::size_t coeff =
+	  (std::numeric_limits<std::size_t>::max()
+	   / std::numeric_limits<long double>::max_exponent);
+
+	result = hibits + (std::size_t)ldval + coeff * exponent;
+
+	return result;
+      }
+    };
 }
 }
 

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]