This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
Re: [Patch] libstdc++/21193 (float, double, long double)
- From: Paolo Carlini <pcarlini at suse dot de>
- To: Paolo Carlini <pcarlini at suse dot de>
- Cc: libstdc++ <libstdc++ at gcc dot gnu dot org>
- Date: Thu, 14 Jul 2005 19:01:54 +0200
- Subject: Re: [Patch] libstdc++/21193 (float, double, long double)
- References: <42D595C4.20205@suse.de>
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;
+ }
+ };
}
}