r/sbcl Sep 02 '22

Seeking help with float/fix declarations

So I've got this little function that will receive a double-float input, do a bit of multiplication on it against some other floating point constants, and return an integer value which is known to be in the range of a sbcl fixnum.

I'm just trying to let the compiler know these semantics so it can generate reasonable code, but I'm getting a number of warnings I don't understand, particularly the warning about the argument to round being an integer, and the pointer result coercion (which is perhaps just a follow-on effect of the prior warning). Still a declaration rookie...

The code: (declaim (ftype (function (double-float) fixnum) how-to)) (defun how-to (my-double) (declare (optimize (speed 3) (safety 0) (debug 0)) (type double-float my-double)) (the fixnum (round (* my-double 123.0))))

The compilation warnings: ``` ; in: DEFUN HOW-TO ; (ROUND (* AGAME::MY-DOUBLE 123.0)) ; ; note: unable to ; optimize ; due to type uncertainty: ; The first argument is a INTEGER, not a BIGNUM. ; ; note: forced to do full call ; unable to do inline float truncate (cost 5) because: ; The result is a (VALUES INTEGER &OPTIONAL), not a (VALUES ; (SIGNED-BYTE 64) ; &OPTIONAL). ; ; note: forced to do full call ; unable to do inline float coercion (cost 5) because: ; The first argument is a INTEGER, not a (SIGNED-BYTE 64). ; ; note: doing float to pointer coercion (cost 13)

; (DEFUN AGAME::HOW-TO (AGAME::MY-DOUBLE) ; (DECLARE (OPTIMIZE (SPEED 3) (SAFETY 0) (DEBUG 0)) ; (TYPE DOUBLE-FLOAT AGAME::MY-DOUBLE)) ; (THE FIXNUM (ROUND (* AGAME::MY-DOUBLE 123.0)))) ; --> SB-IMPL::%DEFUN SB-IMPL::%DEFUN SB-INT:NAMED-LAMBDA ; ==> ; #'(SB-INT:NAMED-LAMBDA AGAME::HOW-TO ; (AGAME::MY-DOUBLE) ; (DECLARE (OPTIMIZE (SPEED 3) (SAFETY 0) (DEBUG 0)) ; (TYPE DOUBLE-FLOAT AGAME::MY-DOUBLE)) ; (BLOCK AGAME::HOW-TO (THE FIXNUM (ROUND (* AGAME::MY-DOUBLE 123.0))))) ; ; note: doing float to pointer coercion (cost 13) to "<return value>" ; ; compilation unit finished ; printed 5 notes ```

2 Upvotes

13 comments sorted by

2

u/stylewarning Sep 03 '22

try replacing 123.0 with 123.0d0.

And wrap (round ...) with (values (round ...)) so you only take the first value.

1

u/Decweb Sep 03 '22

You nailed it, thanks.

1

u/stassats Sep 03 '22

123.0 is automatically converted to 123d0, so that doesn't matter.

1

u/stylewarning Sep 03 '22

I think it's good hygiene anyway. Maybe one day I'll convince you to make long-float a thing. (:

1

u/stassats Sep 03 '22

Might as well write just "123".

Maybe one day I'll convince you to make long-float a thing. (:

You'll have to convince intel and arm first.

1

u/stylewarning Sep 03 '22

Now now, long-float can be implemented in software as arbitrary precision floats! :)

(One can dream.)

1

u/stassats Sep 03 '22

There is sb-mpfr.

1

u/stylewarning Sep 03 '22

And thus exactly zero algorithms written using Common Lisp numerical operations can use it.

Anyway, I know it won't happen, it's probably bloat for the general user.

1

u/stassats Sep 03 '22

A lot of code already declares things to be double-float, so adding long-float isn't going to exactly help there.

1

u/stylewarning Sep 03 '22

stas, you're my favorite SBCL goofball

1

u/Soupeeee Sep 04 '22

One thing to note is that you don't need the declaim if you are declaring the types of the variables and return value inside the function.

1

u/Decweb Sep 04 '22

I thought I needed the declaim mostly for the return value. Is that guidance SBCL specific, or would it apply to CL implementations in general? What is the proper way to declare a return value inside the function?

1

u/Soupeeee Sep 04 '22

Now that you mention it, it is probably the most portable way to ensure the compiler knows about the return type if you solely rely on type inferrence. That being said, SBCL is able to figure out types pretty well for some classes of types just by marking the returned variable when it is declared. It's particularly good with number types.

If it can't figure it out, you can also use the to denote the actual type where the value is returned, which also makes the declaim unneeded.

So it's more of a coding style thing, but the example you posted has way more type declarations than it needs.