2017-02-04 8 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) 

보너스 :

아마도 당신이 기능을하고 유형 선언을 최적화 할 수 있습니다

(disassemble 'invert)를 실행 한 후 나는 SBCL에 다음과 같은 결과를 얻었다
(defun invert (bit) 
    "Inverts a bit" 
    (declare (type bit bit)) 
    (logxor bit 1)) 

:

WITHOUT 형식 선언 :

0 유형 선언으로
; 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 

이 유형 선언이 몇 가지 작업을 저장 한 날 것으로 보인다. 실행하는 동안

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 

:

(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))) 

출력

의 차이를 측정하자

(time (loop repeat 1000000 do (invert-no-dec 1))) 
01 23,516,

출력은 :

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에서 :

인라인 컴파일러에서 function-names로 명명 된 함수에 대한 인라인 호출을 생성하는 것이 바람직하다고 지정합니다. 즉, 지정된 function-name의 코드는 호출 루틴에 통합되어야하며 프로 시저 호출 대신 "in line"으로 나타나야합니다.

+1

"''invert'를 호출하면 성능이 향상 될 것입니다."-'(declaim (inline invert))'를 사용하여 호출을 인라인 할 수 있습니다. – jkiiski

+0

추가되었습니다! 고맙습니다! :) – tsikov

+0

@tsikov : 감사합니다. logxor는 내가 찾고있는 것이었지만 그 중요성은 누락되었습니다. 내가 할 수있는 지금 가정 '(정의-- 수정 매크로 invertf (&) 인수를 휴식 (람다 (비트) (선언 (타입 비트 비트)) (logxor 비트 1)))' 가 선언 및 인라인을 이용하기 ? – davypough