This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
[Patch] libstdc++/21193 (float, double, long double)
- From: Paolo Carlini <pcarlini at suse dot de>
- To: libstdc++ <libstdc++ at gcc dot gnu dot org>
- Date: Thu, 14 Jul 2005 00:29:24 +0200
- Subject: [Patch] libstdc++/21193 (float, double, long double)
Hi,
the below are the float/double/long double bits, as per the discussions
with Gaby and Joe: basically, I'm using the approach suggested by Gaby
when safe and resort to frexp for long double (similarly to various
proposals on the web and python).
Tested x86-linux and, lightly, x86-64-linux.
Paolo.
////////////////
2005-07-14 Paolo Carlini <pcarlini@suse.de>
PR libstdc++/21193 (float, double, long double)
* include/tr1/functional (hash<float>, hash<double>):
Reimplement exploiting the Fnv_hash<>::hash helper.
(hash<long double>): Reimplement using frexp (in this
case, due to random padding bits, the former approach
is not generally viable).
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 13 Jul 2005 21:51:41 -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 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,61 @@
};
#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;
+
+ const long double mult = ((std::numeric_limits<std::size_t>::max()
+ >> 1) + 1.0l);
+ int exponent;
+ ldval = std::frexp(ldval, &exponent);
+ ldval *= mult;
+ const std::size_t hibits = (std::size_t)ldval;
+
+ ldval = (ldval - (long double)hibits) * mult;
+ result = hibits + (std::size_t)ldval + (exponent << 15);
+
+ return result;
+ }
+ };
}
}