aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMattias Engdegård2024-07-04 14:46:54 +0200
committerMattias Engdegård2024-07-04 15:32:45 +0200
commitf9f4f054bc15791ff63252e101dbf08bb4eb33c1 (patch)
tree54413cfb6d646fb526c82ea3f91fa207a34b1593 /src
parent565f4e4ad17c929159d646bfeff7d1adb4c9b727 (diff)
downloademacs-f9f4f054bc15791ff63252e101dbf08bb4eb33c1.tar.gz
emacs-f9f4f054bc15791ff63252e101dbf08bb4eb33c1.zip
Compare fixnums and floats accurately in value<
Make `value<` compare fixnums and floats by value, as `<` does, instead of coercing the fixnum to a float first which is what C would do. This matters when the fixnum cannot be represented as a float. For example, C would evaluate 72057594037927935 < 72057594037927936.0 to false since the operands are converted to the same floating-point number. * src/fns.c (fixnum_float_cmp): New. (value_cmp): Use it. * test/src/fns-tests.el (fns-value<-ordered, fns-value<-unordered): New test cases.
Diffstat (limited to 'src')
-rw-r--r--src/fns.c21
1 files changed, 19 insertions, 2 deletions
diff --git a/src/fns.c b/src/fns.c
index 45567fc183a..61270f0a59f 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -3012,6 +3012,23 @@ bool_vector_cmp (Lisp_Object a, Lisp_Object b)
3012 return (d & aw) ? 1 : -1; 3012 return (d & aw) ? 1 : -1;
3013} 3013}
3014 3014
3015/* Return -1 if a<b, 1 if a>b, 0 if a=b or if b is NaN. */
3016static inline int
3017fixnum_float_cmp (EMACS_INT a, double b)
3018{
3019 double fa = (double)a;
3020 if (fa == b)
3021 {
3022 /* This doesn't mean that a=b because the conversion may have
3023 rounded, but b must be an integer that fits in an EMACS_INT
3024 and we can compare in the integer domain instead. */
3025 EMACS_INT ib = b; /* lossless conversion */
3026 return a < ib ? -1 : a > ib;
3027 }
3028 else
3029 return fa < b ? -1 : fa > b; /* return 0 if b is NaN */
3030}
3031
3015/* Return -1, 0 or 1 to indicate whether a<b, a=b or a>b in the sense of value<. 3032/* Return -1, 0 or 1 to indicate whether a<b, a=b or a>b in the sense of value<.
3016 In particular 0 does not mean equality in the sense of Fequal, only 3033 In particular 0 does not mean equality in the sense of Fequal, only
3017 that the arguments cannot be ordered yet they can be compared (same 3034 that the arguments cannot be ordered yet they can be compared (same
@@ -3035,7 +3052,7 @@ value_cmp (Lisp_Object a, Lisp_Object b, int maxdepth)
3035 if (FIXNUMP (b)) 3052 if (FIXNUMP (b))
3036 return ia < XFIXNUM (b) ? -1 : 1; /* we know that a≠b */ 3053 return ia < XFIXNUM (b) ? -1 : 1; /* we know that a≠b */
3037 if (FLOATP (b)) 3054 if (FLOATP (b))
3038 return ia < XFLOAT_DATA (b) ? -1 : ia > XFLOAT_DATA (b); 3055 return fixnum_float_cmp (ia, XFLOAT_DATA (b));
3039 if (BIGNUMP (b)) 3056 if (BIGNUMP (b))
3040 return -mpz_sgn (*xbignum_val (b)); 3057 return -mpz_sgn (*xbignum_val (b));
3041 } 3058 }
@@ -3176,7 +3193,7 @@ value_cmp (Lisp_Object a, Lisp_Object b, int maxdepth)
3176 if (FLOATP (b)) 3193 if (FLOATP (b))
3177 return fa < XFLOAT_DATA (b) ? -1 : fa > XFLOAT_DATA (b); 3194 return fa < XFLOAT_DATA (b) ? -1 : fa > XFLOAT_DATA (b);
3178 if (FIXNUMP (b)) 3195 if (FIXNUMP (b))
3179 return fa < XFIXNUM (b) ? -1 : fa > XFIXNUM (b); 3196 return -fixnum_float_cmp (XFIXNUM (b), fa);
3180 if (BIGNUMP (b)) 3197 if (BIGNUMP (b))
3181 { 3198 {
3182 if (isnan (fa)) 3199 if (isnan (fa))