2017-02-04 3 views
0

Я не смог найти функцию общего lisp (или макрос), которая просто инвертирует бит. Существуют функции, которые работают с битовыми массивами и логическими функциями, которые работают с числами, но они, похоже, потребуют дополнительных шагов для инверсии одной битовой переменной. Предварительное решениеИнверсия бит

(define-modify-macro invertf (&rest args) 
    (lambda (bit) 
    (if (= bit 0) 1 0))) 

, который работает, но мне было интересно, если есть более элегантный и более простое решение.

ответ

3

Есть много операторов для побитового арифметики:

Например, вы можете использовать

(logxor bit 1) 

Это даст вам 0 если бит равен 1 и 1 если бит равен 0:

(logxor 0 1) ; => 1 
(logxor 1 1) ; => 0 

Конечно, вы можете положить часть bit в качестве второго аргумента:

(logxor 1 bit) 

Bonus:

Может быть, вы можете сделать функцию и оптимизировать его с типом декларации:

(defun invert (bit) 
    "Inverts a bit" 
    (declare (type bit bit)) 
    (logxor bit 1)) 

После запуска (disassemble 'invert) я получил следующие результаты на SBCL:

БЕЗ декларирования типа:

; disassembly for INVERT 
; Size: 56 bytes. Origin: #x10059E97FC 
; 7FC:  498B4C2460  MOV RCX, [R12+96]    ; thread.binding-stack-pointer 
                   ; no-arg-parsing entry point 
; 801:  48894DF8   MOV [RBP-8], RCX 
; 805:  BF02000000  MOV EDI, 2 
; 80A:  488BD3   MOV RDX, RBX 
; 80D:  4883EC18   SUB RSP, 24 
; 811:  48896C2408  MOV [RSP+8], RBP 
; 816:  488D6C2408  LEA RBP, [RSP+8] 
; 81B:  B904000000  MOV ECX, 4 
; 820:  FF1425980B1020 CALL QWORD PTR [#x20100B98]  ; TWO-ARG-XOR 
; 827:  488B5DF0   MOV RBX, [RBP-16] 
; 82B:  488BE5   MOV RSP, RBP 
; 82E:  F8    CLC 
; 82F:  5D    POP RBP 
; 830:  C3    RET 
; 831:  0F0B10   BREAK 16      ; Invalid argument count trap 

С объявлением типа

; disassembly for INVERT 
; Size: 25 bytes. Origin: #x1005767CA9 
; A9:  498B4C2460  MOV RCX, [R12+96]    ; thread.binding-stack-pointer 
                  ; no-arg-parsing entry point 
; AE:  48894DF8   MOV [RBP-8], RCX 
; B2:  488BD3   MOV RDX, RBX 
; B5:  4883F202   XOR RDX, 2 
; B9:  488BE5   MOV RSP, RBP 
; BC:  F8    CLC 
; BD:  5D    POP RBP 
; BE:  C3    RET 
; BF:  0F0B10   BREAK 16       ; Invalid argument count trap 

Мне кажется, что заявление типа сохранили несколько операций.

Замерим разницу:

(defun invert (bit) 
    "Inverts a bit" 
    (declare (type bit bit)) 
    (logxor bit 1)) 

(defun invert-no-dec (bit) 
    "Inverts a bit" 
    (logxor bit 1)) 

Сейчас работает:

(time (loop repeat 1000000 do (invert 1))) 

Выходы:

Evaluation took: 
    0.007 seconds of real time 
    0.005164 seconds of total run time (0.005073 user, 0.000091 system) 
    71.43% CPU 
    14,060,029 processor cycles 
    0 bytes consed 

Во время работы:

(time (loop repeat 1000000 do (invert-no-dec 1))) 

Выходы:

Evaluation took: 
    0.011 seconds of real time 
    0.011327 seconds of total run time (0.011279 user, 0.000048 system) 
    100.00% CPU 
    25,505,355 processor cycles 
    0 bytes consed 

кажется объявление типа делает функцию в два раза быстрее. Следует отметить, что вызов invert, вероятно, компенсирует прирост производительности, если вы не используете (declaim (inline invert)).От CLHS:

inline указывает, что желательно, чтобы компилятор производил встроенные вызовы функций, названных именами функций; то есть код для указанного имени функции должен быть интегрирован в вызывающую подпрограмму, появляясь в строке `` in line '' вместо вызова процедуры.

+1

«вызов инверсии», вероятно, компенсирует усиление в производительности »- вы можете использовать' (declaim (inline invert)) 'для встраивания вызова. – jkiiski

+0

Добавлено! Спасибо! :) – tsikov

+0

@tsikov: Спасибо, logxor был тем, что я искал, но упустил его значение. Предположим теперь, что я могу сделать '(определить изменение-макро invertf (& отдых арг) (лямбда (бит) (объявлять (бит бит типа)) (logxor бит 1)))' воспользоваться деклараций и встраивание ? – davypough

Смежные вопросы