Search code examples
lispcommon-lispsbcl

How to specify a return type of #'sqrt in common lisp?


I'm trying to enable speed optimization is SBCL 2.3.1. Compilation of the following code:

(defun test (x y)
  (declare (optimize speed))
  (declare (type single-float x y))
  (+ x (sqrt y)))

produces the following notes:

; processing (DEFUN TEST ...)

; file: /var/tmp/slimeftWp5F
; in: DEFUN TEST
;     (SQRT RT-SPEC::Y)
; 
; note: unable to
;   optimize
; due to type uncertainty:
;   The result is a (VALUES (OR (COMPLEX SINGLE-FLOAT) (SINGLE-FLOAT -0.0))
;                           &OPTIONAL), not a (VALUES FLOAT &REST T).

;     (+ RT-SPEC::X (SQRT RT-SPEC::Y))
; 
; note: forced to do GENERIC-+ (cost 10)
;       unable to do inline float arithmetic (cost 2) because:
;       The second argument is a (OR (COMPLEX SINGLE-FLOAT) (SINGLE-FLOAT -0.0)), not a SINGLE-FLOAT.
;       The result is a (VALUES (OR SINGLE-FLOAT (COMPLEX SINGLE-FLOAT))
;                               &OPTIONAL), not a (VALUES SINGLE-FLOAT &OPTIONAL).
;       unable to do inline float arithmetic (cost 3) because:
;       The second argument is a (OR (COMPLEX SINGLE-FLOAT) (SINGLE-FLOAT -0.0)), not a (COMPLEX
;                                                                                        SINGLE-FLOAT).
;       The result is a (VALUES (OR SINGLE-FLOAT (COMPLEX SINGLE-FLOAT))
;                               &OPTIONAL), not a (VALUES (COMPLEX SINGLE-FLOAT)
;                                                         &OPTIONAL).
; 
; compilation unit finished
;   printed 2 notes

If I'm understanding correctly, the generic #'sqrt function may return values of different types. But I'm supplying a single-float argument to it, is it possible somehow to specify what the return type must be single-float?


Solution

  • If y is negative, the square root will be a complex value:

    > (test 1.5 -3.2)
    #C(1.5 1.7888544)
    

    If you want to restrict your floats to positive or zero values, you can use the compound type specifier:

    single-float [single-lower-limit [single-upper-limit]]

    For example, as follows:

    (defun test (x y)
      (declare (optimize (speed 3)))
      (declare (type (single-float 0.0) x y))
      (+ x (sqrt y)))
    

    There is no warning in that case for me.