Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

check if unsigned numbers underflow #1025

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

Jobhdez
Copy link
Contributor

@Jobhdez Jobhdez commented Oct 18, 2023

@Izaakwltn Hopefully this is not an issue that I made another pr. I had git issues with the other one.

This solves #921.

This is the interaction I just had in this new pr:

(coalton-toplevel 
		(declare add-8bit (U8 -> U8 -> U8))
		(define (add-8bit x y)
		  (+ x y))
		(declare sub-8bit (U8 -> U8 -> U8))
		(define (sub-8bit x y)
		  (- x y))
		(declare mul-8bit (U8 -> U8 -> U8))
		(define (mul-8bit x y)
		  (* x y))
		(declare fint (Integer -> U8))
		(define (fint x)
		  (fromInt x)))
; No value
COALTON-USER> (coalton (add-8bit 2 3))
5
COALTON-USER> (coalton (add-8bit 3 -4))
; Evaluation aborted on #<SIMPLE-ERROR "Unsigned value underflowed 8 bits." {1007939573}>.
COALTON-USER> (coalton (sub-8bit 3 2))
1
COALTON-USER> (coalton (sub-8bit 3 5))
; Evaluation aborted on #<SIMPLE-ERROR "Unsigned value underflowed 8 bits." {100835E453}>.
COALTON-USER> (coalton (mul-8bit 3 4))
12
COALTON-USER> (coalton (mul-8bit 3 -4))
; Evaluation aborted on #<SIMPLE-ERROR "Unsigned value underflowed 8 bits." {1008C8C2B3}>.
COALTON-USER> (coalton (fint 4))
4
COALTON-USER> (coalton (fint -2))
; Evaluation aborted on #<SIMPLE-ERROR "Unsigned value underflowed 8 bits." {10017D9693}>.

Thanks

@Izaakwltn
Copy link
Collaborator

I tested it and this provides correct underflow errors.

I think it would make sense to use cl:error instead of cl:cerror, and remove the continue-format-string since there is no wrapping operation defined. Currently, if you select 0: [CONTINUE] Continue, wrapping around. in the debugger, you get another error because it's still expecting a number and isn't getting one:

The value
  COMMON-LISP:NIL
is not of type
  (UNSIGNED-BYTE 16)
   [Condition of type COMMON-LISP:TYPE-ERROR]

Otherwise, this seems solid.

@Izaakwltn
Copy link
Collaborator

Looks good to me! I have no gripes.

I think there should be a future issue to have unsigned numbers error on overflow too, but that can be a separate thing.

I'm going to approve it but I'll wait to see if anyone else wants to review it before merging.

Copy link
Member

@stylewarning stylewarning left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR on the whole isn't structured correctly. We are defining Num for the same unsigned types multiple times, once for wrapping behavior, and then for underflow behavior. We can only define them once.

library/math/num.lisp Outdated Show resolved Hide resolved
library/math/num.lisp Outdated Show resolved Hide resolved
`(define-instance (Num ,type)
(define (+ a b)
(lisp ,type (a b)
(cl:if (cl:and (cl:< b 0) (cl:< a (cl:- 0 b)))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(< x 0) ==> (minusp x)

(- 0 x) ==> (- x)


(define (- a b)
(lisp ,type (a b)
(cl:if (cl:and (cl:>= b 0) (cl:< a (cl:+ 0 b)))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

b is guaranteed >= 0 for unsigned numbers

`(define-instance (Num ,type)
(define (+ a b)
(lisp ,type (a b)
(cl:if (cl:and (cl:< b 0) (cl:< a (cl:- 0 b)))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

b can never be negative for unsigned numbers


(define (* a b)
(lisp ,type (a b)
(cl:if (cl:or (cl:and (cl:and (cl:> b 0) (cl:< a 0)) (cl:< a (cl:/ 0 b)))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unsigned multiplication can't underflow

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what do you mean by this? are you saying the code that i wrote doesnt detect the underflow or that in general unsigned multiplication doesnt underflow?

wouldnt this be an underflow: 2 * -3?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-3 isn't an unsigned number

@stylewarning
Copy link
Member

(Incidentally this means we have no tests that actually look for correct overflow / underflow behavior.)

@Jobhdez
Copy link
Contributor Author

Jobhdez commented Oct 19, 2023

@stylewarning thank you for this.

I will try to address your review as soon as I can. Thanks.

For the wrapper, I just have to make it so when the unsigned values underflow, the user can continue, if they want, with the highest number possible of the given unsigned type right?

so if two addition of U8 integers underflow, the wrapper needs to allow the user continue from the error with the wrapped number which in this case would be 255? correct? ust trying to make sure I am thinking the right thing. thanks

library/math/num.lisp Outdated Show resolved Hide resolved
library/math/num.lisp Outdated Show resolved Hide resolved
@Jobhdez
Copy link
Contributor Author

Jobhdez commented Oct 20, 2023

@Izaakwltn addressed your review

Copy link
Member

@stylewarning stylewarning left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your patience in review.

This PR needs to modify define-num-wrapping's definition of - and fromInt only. Adding another define macro is not needed (and is actually redundant), and the other "handler" functionality is not all that useful outside of the scope of this change, so it can be eliminated.

@@ -161,6 +161,47 @@
;;; Num instances for integers
;;;

(cl:defmacro %define-unsigned-underflow-handler (name bits)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think this can be deleted

(64 (cl:the (cl:unsigned-byte ,bits) 18446744073709551615)))))


(%define-unsigned-underflow-handler %unsigned-8-bit-underflow-handler 8)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these can be deleted

(define-num-wrapping UFix #.+unsigned-fixnum-bits+))
(define-num-wrapping UFix #.+unsigned-fixnum-bits+)

(define-unsigned-num-underflow U8 %unsigned-8-bit-underflow-handler 8)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these are re-defining Num for types that already have it. Above, define-num-wrapping is already defining - and the like for each of the listed types.

@Jobhdez
Copy link
Contributor Author

Jobhdez commented Feb 2, 2024

Thanks for your patience in review.

This PR needs to modify define-num-wrapping's definition of - and fromInt only. Adding another define macro is not needed (and is actually redundant), and the other "handler" functionality is not all that useful outside of the scope of this change, so it can be eliminated.

mybad for the late reply. But your comment means that I only pretty much have take what I wrote in my function and move to the define-num-wrapping function? thanks

@stylewarning
Copy link
Member

Yes, essentially.

@Jobhdez
Copy link
Contributor Author

Jobhdez commented Feb 2, 2024

Yes, essentially.

Ok I’ll get it done ASAP.

@Izaakwltn
Copy link
Collaborator

Izaakwltn commented Mar 4, 2024

At least one test failing due to the ecase, specifically in test iter-min-max:

While evaluating the form starting at line 3, column 0
  of #P"/__w/coalton/coalton/run-tests.lisp":
Unhandled SB-KERNEL:CASE-FAILURE in thread #<SB-THREAD:THREAD "main thread" RUNNING
                                              {1001090073}>:
  62 fell through COMMON-LISP:ECASE expression. Wanted one of (8 16 32 64).

Your ecase can get matches for bits that aren't 8, 16, 32, or 64.

I would recommend loading the coalton test suite and either running all tests locally or just running iter-min-max to debug.

Edit: in terms of the failing iterator test, I think the culprit is behavior in iter:range-decreasing.

@Izaakwltn
Copy link
Collaborator

I think +unsigned-fixnum-bits+ is sbcl specific, so the tests are passing in SBCL but still not in the other implementations:

Allegro:
https://github.com/coalton-lang/coalton/actions/runs/8151586516/job/22279665406?pr=1025#step:5:507

CCL:
https://github.com/coalton-lang/coalton/actions/runs/8151586516/job/22279665807?pr=1025#step:6:434

You might be able to do an #+sbcl exception for that approach and find another way to handle the other implementations, but if you find a uniform solution for all three types that would be optimal.

@Jobhdez Jobhdez closed this Mar 7, 2024
@Jobhdez Jobhdez reopened this Mar 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants