Ну, компилятор говорит вам ответ, возможно, немного бесполезно. Если у вас есть два фикснума, то это не тот случай, когда, например, их добавление приводит к фиксиннуму: тип fixnum
не закрывается при арифметических операциях (даже при +
, -
и *
,пренебрегая /
).
Из руководства SBCL :
Компилятор SBCL трактует объявления типов иначе, чем большинство других компиляторов Lisp. В соответствии с политикой компиляции по умолчанию компилятор не верит слепо в объявления объявлений типов, а рассматривает их как утверждения о программе, которые должны быть проверены: все объявления типов, которые не всегда поддерживаются, создаются во время выполнения.
Что вам нужно сделать, если вы хотите скомпилировать машинную арифметику, так это сообщить компилятору, что используемые им типы достаточно хороши, чтобы он мог знать, что типы результатов достаточно хороши и могут быть представлены немедленно.
Учитывая арифметику, которую вы имеете в функции, и предполагая 64-битную реализацию, тогда хорошим типом будет (signed-byte 31)
: заманчиво использовать (signed-byte 32)
, но это не получается, потому что вы в конечном итоге получаете нечто большее, чем (signed-byte 64)
.
Таким образом, этот код не предупреждает, за исключением обработки последнего двойного числа с плавающей точкой при возврате:
(deftype smallish-integer (&optional (bits 31))
`(signed-byte ,bits))
(declaim (ftype (function (smallish-integer smallish-integer) double-float)
fixnumtest)
(inline fixnumtest))
(defun fixnumtest (i j)
(declare (optimize (speed 2)))
(declare (type smallish-integer i j))
(let* ((n (+ i j))
(n+1 (1+ n)))
(/ 1.0d0 (* n n+1))))
Стоит отметить, что (signed-byte 64)
намного больше, чем fixnum
: это нормально, потому что внутри функции компилятор может справиться с числами, которые вписываются в регистрrs, хотя они больше, чем fixnums.
Я недостаточно знаком с ассемблером x64, чтобы проверить, что вся арифметика скомпилирована как машинные инструкции, но выглядит так.
Можетможно было бы убедить компилятор SBCL в том, что вам не нужен правильный ответ и что он должен просто выполнять машинную арифметику, даже если он знает, что он может переполниться. Я понятия не имею, как это сделать.