If a bignum exceeds the largest representable single-float, EQUALP will raise a type-error when comparing it to a single-float. The same problem happens with double-floats.
I am reporting this because my understanding of CLHS http://www.lispworks.com/documentation/lw51/CLHS/Body/f_equalp.htm#equalp tells that EQUALP is not supposed to raise errors at all: "Exceptional Situations: None."
How to reproduce:
;; =========== double-floats =========== (= (ash 1 1024) most-positive-double-float) NIL
(equalp (ash 1 1024) most-positive-double-float) ; Evaluation aborted on #<TYPE-ERROR {215F90FE}>.
;; =========== single-floats =========== (= 340282360000000000000000000000000000000 0.0f0) NIL
(equalp 340282360000000000000000000000000000000 0.0f0) ; Evaluation aborted on #<TYPE-ERROR {1CFFC364}>.
In attachment the detailed stacktrace and a proposed patch to fix this problem.
Regards,
Massimiliano Ghilardi
_______________________________________________ Armedbear-devel mailing list Armedbear-devel@common-lisp.net http://mailman.common-lisp.net/cgi-bin/mailman/listinfo/armedbear-devel
On 25 Jan 2015, at 20:19, Massimiliano Ghilardi massimiliano.ghilardi+abcl@gmail.com wrote:
Massimiliano Ghilardi
Nice fix. Promoted as [14749][].
Need to release a abcl-1.3.2 real soon now…
[14749]: http://abcl.org/trac/changeset/14749
On 01/26/15 07:40, Mark Evenson wrote:
On 25 Jan 2015, at 20:19, Massimiliano Ghilardi massimiliano.ghilardi+abcl@gmail.com wrote:
Massimiliano Ghilardi
Nice fix. Promoted as [14749][].
Need to release a abcl-1.3.2 real soon now…
Thanks Mark.
My patch stops EQUALP from signaling errors on "impossible" bignum-to-float comparisons, i.e. between floats and bignums larger than the biggest representable floats.
Anyway, it does not fix an existing bug for "possible" comparisons, i.e. between floats and bignums in the range representable by floats.
The usual CLHS file:///home/max/SW/lisp/docs-lisp/HyperSpec/Body/f_equalp.htm#equalp tells that EQUALP on two numbers is the same as =.
There are cases where ABCL does not follow it:
CL-USER> (= most-positive-single-float 340282346638528859811704183484516925440) T
CL-USER> (equalp most-positive-single-float 340282346638528859811704183484516925440) T ;; correct :)
CL-USER> (= most-positive-single-float 340282346638528859811704183484516925439) NIL
EQUALP behaves differently from =, because (EQUALP bignum float) converts the bignum to float, losing precision:
CL-USER> (equalp most-positive-single-float 340282346638528859811704183484516925439) T ;; incorrect :(
Digging more reveals further inconsistencies...
CL-USER> (= 1.0 #C(1.0 0.0)) T
CL-USER> (equalp 1.0 #C(1.0 0.0)) NIL ;; again :(
The fix is conceptually simple: for all the number tower, EQUALP must use the same algorithm as =, with the only difference that it must never throw.
I am not sure which Java method implements the function = so I don't dare yet to write a patch. Maybe isEqualTo() ?
Regards,
Massimiliano Ghilardi
Hi Massimiliano,
On Tue, Jan 27, 2015 at 11:38 PM, Massimiliano Ghilardi < massimiliano.ghilardi+abcl@gmail.com> wrote:
On 01/26/15 07:40, Mark Evenson wrote:
On 25 Jan 2015, at 20:19, Massimiliano Ghilardi <
massimiliano.ghilardi+abcl@gmail.com> wrote:
Massimiliano Ghilardi
Nice fix. Promoted as [14749][].
Need to release a abcl-1.3.2 real soon now…
Thanks Mark.
My patch stops EQUALP from signaling errors on "impossible" bignum-to-float comparisons, i.e. between floats and bignums larger than the biggest representable floats.
Anyway, it does not fix an existing bug for "possible" comparisons, i.e. between floats and bignums in the range representable by floats.
The usual CLHS file:///home/max/SW/lisp/docs-lisp/HyperSpec/Body/f_equalp.htm#equalp tells that EQUALP on two numbers is the same as =.
There are cases where ABCL does not follow it:
CL-USER> (= most-positive-single-float 340282346638528859811704183484 516925440) T
CL-USER> (equalp most-positive-single-float 340282346638528859811704183484 516925440) T ;; correct :)
CL-USER> (= most-positive-single-float 340282346638528859811704183484 516925439) NIL
EQUALP behaves differently from =, because (EQUALP bignum float) converts the bignum to float, losing precision:
CL-USER> (equalp most-positive-single-float 340282346638528859811704183484 516925439) T ;; incorrect :(
Digging more reveals further inconsistencies...
CL-USER> (= 1.0 #C(1.0 0.0)) T
CL-USER> (equalp 1.0 #C(1.0 0.0)) NIL ;; again :(
The fix is conceptually simple: for all the number tower, EQUALP must use the same algorithm as =, with the only difference that it must never throw.
I am not sure which Java method implements the function = so I don't dare yet to write a patch. Maybe isEqualTo() ?
Right on the mark! See Primitives.java#L1235 and compiler-pass2.lisp:p2-numeric-comparison ; the former for interpreted code, the latter for compiled code.
Thanks for taking the time to submit patches!
Hello,
my previous patch fixed some cases where EQUALP signaled errors, but was not a full solution. In attachment you can find a second patch, to be applied on top of the first one, to fix the remaining EQUALP issues.
It solves the problems shown by the following test:
(loop for x in (list most-positive-single-float most-positive-double-float) do (loop for y in (list (1- (ash #xFFFFFF 104)) (ash #xFFFFFF 104) (1- (ash #xFFFFFFFFFFFFF8 968)) (ash #xFFFFFFFFFFFFF8 968) (ash 1 1024) (/ (ash 1 1026) 3)) do (handler-case (format t "~S ~S ~S ~S~%" (= x y) (= x y) (equalp x y) (equalp y x)) (condition (c) (format t "error: ~A~%" c)))))
On SBCL and CLISP, this test correctly prints (due to 32-bit IEEE single-floats and 64-bit IEEE double-floats) : ---------------------------------------------------------- NIL NIL NIL NIL T T T T NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL T T T T NIL NIL NIL NIL NIL NIL NIL NIL ----------------------------------------------------------
After applying my first patch, ABCL 1.3.1 prints: ---------------------------------------------------------- NIL NIL T T ;; note: EQUALP and = disagree T T T T error: The value 1797... is too large to be converted to a single float. error: The value 1797... is too large to be converted to a single float. error: The value 1797... is too large to be converted to a single float. error: The value 7190.../3 is not of type DOUBLE-FLOAT. NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL T T ;; note: EQUALP and = disagree again T T T T error: The value 1797... is too large to be converted to a double float. error: The value 7190.../3 is not of type DOUBLE-FLOAT. ----------------------------------------------------------
that is quite clearly bugged, since CLHS states: 1) for numbers, EQUALP is the same as = 2) EQUALP must never signal errors
(without my first patch, the outcome is worse).
With the second patch in attachment, this test succeeds on ABCL too.
I hope you will appreciate the irony that I *removed* code instead of adding it...
Regards,
Massimiliano Ghilardi
_______________________________________________ Armedbear-devel mailing list Armedbear-devel@common-lisp.net https://mailman.common-lisp.net/cgi-bin/mailman/listinfo/armedbear-devel
On 03 Mar 2015, at 22:13, Massimiliano Ghilardi massimiliano.ghilardi+abcl@gmail.com wrote:
Hello,
my previous patch fixed some cases where EQUALP signaled errors, but was not a full solution. In attachment you can find a second patch, to be applied on top of the first one, to fix the remaining EQUALP issues.
[…]
Thanks for the improved patch. It has been applied as [r14750][1].
[1]: http://abcl.org/trac/changeset/14750
On 01/26/15 07:40, Mark Evenson wrote:
On 25 Jan 2015, at 20:19, Massimiliano Ghilardi massimiliano.ghilardi+abcl@gmail.com wrote:
Massimiliano Ghilardi
Nice fix. Promoted as [14749][].
Need to release a abcl-1.3.2 real soon now…
Thanks Mark.
My patch stops EQUALP from signaling errors on "impossible" bignum-to-float comparisons, i.e. between floats and bignums larger than the biggest representable floats.
Anyway, it does not fix an existing bug for "possible" comparisons, i.e. between floats and bignums in the range representable by floats.
The usual CLHS file:///home/max/SW/lisp/docs-lisp/HyperSpec/Body/f_equalp.htm#equalp tells that EQUALP on two numbers is the same as =.
There are cases where ABCL does not follow it:
CL-USER> (= most-positive-single-float 340282346638528859811704183484516925440) T
CL-USER> (equalp most-positive-single-float 340282346638528859811704183484516925440) T ;; correct :)
CL-USER> (= most-positive-single-float 340282346638528859811704183484516925439) NIL
EQUALP behaves differently from =, because (EQUALP bignum float) converts the bignum to float, losing precision:
CL-USER> (equalp most-positive-single-float 340282346638528859811704183484516925439) T ;; incorrect :(
Digging more reveals further inconsistencies...
CL-USER> (= 1.0 #C(1.0 0.0)) T
CL-USER> (equalp 1.0 #C(1.0 0.0)) NIL ;; again :(
The fix is conceptually simple: for all the number tower, EQUALP must use the same algorithm as =, with the only difference that it must never throw.
I am not sure which Java method implements the function = so I don't dare yet to write a patch. Maybe isEqualTo() ?
Regards,
Massimiliano Ghilardi
armedbear-devel@common-lisp.net