aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/beam
diff options
context:
space:
mode:
authorBjörn-Egil Dahlberg <[email protected]>2015-04-01 15:30:12 +0200
committerBjörn-Egil Dahlberg <[email protected]>2015-04-10 15:50:36 +0200
commit2a0ff8b50a68d51e44fddf36867f390b64a4f2bf (patch)
treed9d090305c992874320ca19dcf9381259e0b8088 /erts/emulator/beam
parentcc722af4d62d749d2a75155e91a2a1562aeb2a5a (diff)
downloadotp-2a0ff8b50a68d51e44fddf36867f390b64a4f2bf.tar.gz
otp-2a0ff8b50a68d51e44fddf36867f390b64a4f2bf.tar.bz2
otp-2a0ff8b50a68d51e44fddf36867f390b64a4f2bf.zip
erts: Ensure hashing of zero is consistent
Erlang treats positive and negative zero as equal, meaning, true = 0.0 =:= 0.0/-1 However, Erlangs hash functions: hash, phash and phash2 did not reflect this behaviour. Meaning, the hash values produced by the different hash functions would not be identical for positive and negative zero. This commit ensures that hash value of positive zero is always produced regardless of the signedness of the zero float, i.e. true = erlang:phash2(0.0) =:= erlang:phash2(0.0/-1)
Diffstat (limited to 'erts/emulator/beam')
-rw-r--r--erts/emulator/beam/utils.c29
1 files changed, 18 insertions, 11 deletions
diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c
index 2dd81e3ca3..2018518bf3 100644
--- a/erts/emulator/beam/utils.c
+++ b/erts/emulator/beam/utils.c
@@ -955,12 +955,14 @@ tail_recur:
UINT32_HASH_RET(external_ref_numbers(term)[0],FUNNY_NUMBER9,FUNNY_NUMBER10);
case FLOAT_DEF:
{
- FloatDef ff;
- GET_DOUBLE(term, ff);
- hash = hash*FUNNY_NUMBER6 + (ff.fw[0] ^ ff.fw[1]);
- break;
+ FloatDef ff;
+ GET_DOUBLE(term, ff);
+ if (ff.fd == 0.0f) {
+ ff.fd = 0.0f; /* ensure pos. 0.0 */
+ }
+ hash = hash*FUNNY_NUMBER6 + (ff.fw[0] ^ ff.fw[1]);
+ break;
}
-
case MAKE_HASH_CDR_PRE_OP:
term = (Eterm) WSTACK_POP(stack);
if (is_not_list(term)) {
@@ -1474,6 +1476,9 @@ make_hash2(Eterm term)
{
FloatDef ff;
GET_DOUBLE(term, ff);
+ if (ff.fd == 0.0f) {
+ ff.fd = 0.0f; /* ensure pos. 0.0 */
+ }
#if defined(WORDS_BIGENDIAN) || defined(DOUBLE_MIDDLE_ENDIAN)
UINT32_HASH_2(ff.fw[0], ff.fw[1], HCONST_12);
#else
@@ -1893,8 +1898,8 @@ make_internal_hash(Eterm term)
{
FloatDef ff;
GET_DOUBLE(term, ff);
- if (ff.fd == 0.0) {
- ff.fd = 0.0; /* ensure pos. 0.0 */
+ if (ff.fd == 0.0f) {
+ ff.fd = 0.0f; /* ensure pos. 0.0 */
}
UINT32_HASH_2(ff.fw[0], ff.fw[1], HCONST_12);
goto pop_next;
@@ -2079,12 +2084,14 @@ tail_recur:
break;
case FLOAT_DEF:
{
- FloatDef ff;
- GET_DOUBLE(term, ff);
- hash = hash*FUNNY_NUMBER6 + (ff.fw[0] ^ ff.fw[1]);
+ FloatDef ff;
+ GET_DOUBLE(term, ff);
+ if (ff.fd == 0.0f) {
+ ff.fd = 0.0f; /* ensure pos. 0.0 */
+ }
+ hash = hash*FUNNY_NUMBER6 + (ff.fw[0] ^ ff.fw[1]);
}
break;
-
case MAKE_HASH_CDR_PRE_OP:
term = (Eterm) WSTACK_POP(stack);
if (is_not_list(term)) {