aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/beam/utils.c
diff options
context:
space:
mode:
authorLukas Larsson <[email protected]>2011-07-26 17:11:41 +0200
committerLukas Larsson <[email protected]>2011-10-11 17:10:19 +0200
commite04883d448df6e622535020449903e2f2a0f32c9 (patch)
treec7db6e79663481ff9e9f1cb2b79b86cfe61cfec9 /erts/emulator/beam/utils.c
parent622daf3b96666f8bbabec44a15b26a188a83b95e (diff)
downloadotp-e04883d448df6e622535020449903e2f2a0f32c9.tar.gz
otp-e04883d448df6e622535020449903e2f2a0f32c9.tar.bz2
otp-e04883d448df6e622535020449903e2f2a0f32c9.zip
Update integer and floating point number comparisons
For floating point values which are greater than 9007199254740990.0 or smaller than -9007199254740990.0, the floating point numbers are now converted to integers during comparison with an integer. This makes number comparisons transitive for large floating point numbers.
Diffstat (limited to 'erts/emulator/beam/utils.c')
-rw-r--r--erts/emulator/beam/utils.c59
1 files changed, 48 insertions, 11 deletions
diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c
index 3f6accba2d..e67a793b9a 100644
--- a/erts/emulator/beam/utils.c
+++ b/erts/emulator/beam/utils.c
@@ -2642,7 +2642,7 @@ tailrecur_ne:
FloatDef f1, f2;
Eterm big;
#if HEAP_ON_C_STACK
- Eterm big_buf[2]; /* If HEAP_ON_C_STACK */
+ Eterm big_buf[16]; /* If HEAP_ON_C_STACK */
#else
Eterm *big_buf = erts_get_scheduler_data()->cmp_tmp_heap;
#endif
@@ -2661,33 +2661,70 @@ tailrecur_ne:
j = big_comp(big, bw);
break;
case SMALL_FLOAT:
- f1.fd = signed_val(a);
GET_DOUBLE(bw, f2);
- j = float_comp(f1.fd, f2.fd);
+ if ((f2.fd < 9007199254740990.0 && f2.fd > -9007199254740990.0)) // Float is within the no loss limit
+ {
+ f1.fd = signed_val(a);
+ j = float_comp(f1.fd, f2.fd);
+ } else if (f2.fd > (double) (MAX_SMALL + 1)) { // Float is a positive bignum, i.e. bigger
+ j = -1;
+ } else if (f2.fd < (double) (MIN_SMALL - 1)) { // Float is a negative bignum, i.e. smaller
+ j = 1;
+ } else { // Float is a Sint but less precise it
+ j = signed_val(a) - (Sint) f2.fd;
+ }
break;
case BIG_SMALL:
big = small_to_big(signed_val(b), big_buf);
j = big_comp(aw, big);
break;
case BIG_FLOAT:
- if (big_to_double(aw, &f1.fd) < 0) {
+ GET_DOUBLE(bw, f2);
+ if ((f2.fd < 9007199254740990.0 && f2.fd > -9007199254740990.0)) {
+ if (big_to_double(aw, &f1.fd) < 0) {
+ j = big_sign(a) ? -1 : 1;
+ } else {
+ j = float_comp(f1.fd, f2.fd);
+ }
+ } else if ((f2.fd < (double) (MAX_SMALL + 1)) && (f2.fd > (double) (MIN_SMALL - 1))) { // Float is a Sint
+ j = big_sign(a) ? -1 : 1;
+ } else if (big_arity(a) > ((1 << 10) / D_EXP)) { // If bignum size is larger than largest/smallest float
j = big_sign(a) ? -1 : 1;
} else {
- GET_DOUBLE(bw, f2);
- j = float_comp(f1.fd, f2.fd);
+ big = double_to_big(f2.fd, big_buf);
+ j = big_comp(aw, big);
}
break;
case FLOAT_SMALL:
GET_DOUBLE(aw, f1);
- f2.fd = signed_val(b);
- j = float_comp(f1.fd, f2.fd);
+ if ((f1.fd < 9007199254740990.0 && f1.fd > -9007199254740990.0)) // Float is within the no loss limit
+ {
+ f2.fd = signed_val(b);
+ j = float_comp(f1.fd, f2.fd);
+ } else if (f1.fd > (double) (MAX_SMALL + 1)) { // Float is a positive bignum, i.e. bigger
+ j = 1;
+ } else if (f1.fd < (double) (MIN_SMALL - 1)) { // Float is a negative bignum, i.e. smaller
+ j = -1;
+ } else { // Float is a Sint but less precise it
+ j = (Sint) f1.fd - signed_val(b);
+ }
break;
case FLOAT_BIG:
- if (big_to_double(bw, &f2.fd) < 0) {
+ GET_DOUBLE(aw, f1);
+ if ((f1.fd < 9007199254740990.0 && f1.fd > -9007199254740990.0)) {
+ if (big_to_double(bw, &f2.fd) < 0) {
+ j = big_sign(b) ? 1 : -1;
+ } else {
+ j = float_comp(f1.fd, f2.fd);
+ }
+ } else if ((f1.fd < (double) (MAX_SMALL + 1))
+ && (f1.fd > (double) (MIN_SMALL - 1))) { // Float is a Sint
+ j = big_sign(b) ? 1 : -1;
+ } else if (big_arity(b) > ((1 << 10) / D_EXP)) { // If bignum size is larger than largest/smallest float
j = big_sign(b) ? 1 : -1;
} else {
- GET_DOUBLE(aw, f1);
- j = float_comp(f1.fd, f2.fd);
+ big = double_to_big(f1.fd, big_buf);
+ j = big_comp(big, bw);
}
break;
default: