Name: Anonymous 2013-12-14 17:42
How would you implement it without breaking homoiconicity?
(declaim (ftype (function ((unsigned-byte 64)) (values (unsigned-byte 64) &optional))
shuffle))
(defun shuffle (x)
(flet ((one-round (x mask shift)
(ldb (byte 64 0)
(logior (ash (logand x mask) shift)
(logand (ash x (- shift)) mask)
(logandc2 x (logior mask (ash mask shift)))))))
(declare (inline one-round))
(let* ((k1 (one-round x #x00000000FFFF0000 16))
(k2 (one-round k1 #x0000FF000000FF00 8))
(k3 (one-round k2 #x00F000F000F000F0 4))
(k4 (one-round k3 #x0C0C0C0C0C0C0C0C 2))
(k5 (one-round k4 #x2222222222222222 1)))
k5)))
CL-USER> (format t "~2r~%" (shuffle #x00000000FFFFFFFF))
101010101010101010101010101010101010101010101010101010101010101
CL-USER> (disassemble 'shuffle)
; disassembly for SHUFFLE
; Size: 424 bytes
; 05772DB0: 488D0409 LEA RAX, [RCX+RCX] ; no-arg-parsing entry point
; DB4: 4823054D010000 AND RAX, [RIP+333] ; #x1FFFE0000
; DBB: 488BD0 MOV RDX, RAX
; DBE: 48C1E210 SHL RDX, 16
; DC2: 488BC1 MOV RAX, RCX
; DC5: 48C1E810 SHR RAX, 16
; DC9: 48D1E0 SHL RAX, 1
; DCC: 48230535010000 AND RAX, [RIP+309] ; #x1FFFE0000
; DD3: 4809C2 OR RDX, RAX
; DD6: 488BD9 MOV RBX, RCX
; DD9: 48231D30010000 AND RBX, [RIP+304] ; #xFFFF00000000FFFF
; DE0: 488BC2 MOV RAX, RDX
; DE3: 48D1F8 SAR RAX, 1
; DE6: 4809D8 OR RAX, RBX
; DE9: 488D1400 LEA RDX, [RAX+RAX]
; DED: 48231524010000 AND RDX, [RIP+292] ; #x1FE000001FE00
; DF4: 488BDA MOV RBX, RDX
; DF7: 48C1E308 SHL RBX, 8
; DFB: 488BD0 MOV RDX, RAX
; DFE: 48C1EA08 SHR RDX, 8
; E02: 48D1E2 SHL RDX, 1
; E05: 4823150C010000 AND RDX, [RIP+268] ; #x1FE000001FE00
; E0C: 4809D3 OR RBX, RDX
; E0F: 488BD0 MOV RDX, RAX
; E12: 48231507010000 AND RDX, [RIP+263] ; #xFF0000FFFF0000FF
; E19: 488BC3 MOV RAX, RBX
; E1C: 48D1F8 SAR RAX, 1
; E1F: 4809D0 OR RAX, RDX
; E22: 488D1400 LEA RDX, [RAX+RAX]
; E26: 482315FB000000 AND RDX, [RIP+251] ; #x1E001E001E001E0
; E2D: 488BDA MOV RBX, RDX
; E30: 48C1E304 SHL RBX, 4
; E34: 488BD0 MOV RDX, RAX
; E37: 48C1EA04 SHR RDX, 4
; E3B: 48D1E2 SHL RDX, 1
; E3E: 482315E3000000 AND RDX, [RIP+227] ; #x1E001E001E001E0
; E45: 4809D3 OR RBX, RDX
; E48: 488BD0 MOV RDX, RAX
; E4B: 482315DE000000 AND RDX, [RIP+222] ; #xF00FF00FF00FF00F
; E52: 488BC3 MOV RAX, RBX
; E55: 48D1F8 SAR RAX, 1
; E58: 4809D0 OR RAX, RDX
; E5B: 488D1400 LEA RDX, [RAX+RAX]
; E5F: 482315D2000000 AND RDX, [RIP+210] ; #x1818181818181818
; E66: 488D1C9500000000 LEA RBX, [RDX*4]
; E6E: 488BD0 MOV RDX, RAX
; E71: 48C1EA02 SHR RDX, 2
; E75: 48D1E2 SHL RDX, 1
; E78: 482315B9000000 AND RDX, [RIP+185] ; #x1818181818181818
; E7F: 4809D3 OR RBX, RDX
; E82: 488BD0 MOV RDX, RAX
; E85: 482315B4000000 AND RDX, [RIP+180] ; #xC3C3C3C3C3C3C3C3
; E8C: 488BC3 MOV RAX, RBX
; E8F: 48D1F8 SAR RAX, 1
; E92: 4809D0 OR RAX, RDX
; E95: 488D1400 LEA RDX, [RAX+RAX]
; E99: 482315A8000000 AND RDX, [RIP+168] ; #x4444444444444444
; EA0: 48D1FA SAR RDX, 1
; EA3: 48D1E2 SHL RDX, 1
; EA6: 488BDA MOV RBX, RDX
; EA9: 488BD0 MOV RDX, RAX
; EAC: 48D1EA SHR RDX, 1
; EAF: 48D1E2 SHL RDX, 1
; EB2: 4823158F000000 AND RDX, [RIP+143] ; #x4444444444444444
; EB9: 48D1FA SAR RDX, 1
; EBC: 4809D3 OR RBX, RDX
; EBF: 4823058A000000 AND RAX, [RIP+138] ; #x9999999999999999
; EC6: 4809C3 OR RBX, RAX
; EC9: 48BA00000000000000C0 MOV RDX, -4611686018427387904
; ED3: 4885DA TEST RBX, RDX
; ED6: 488D141B LEA RDX, [RBX+RBX]
; EDA: 740E JEQ L0
; EDC: 488BD3 MOV RDX, RBX
; EDF: 4C8D1C256B090020 LEA R11, [#x2000096B] ; ALLOC-UNSIGNED-BIGNUM-IN-RDX
; EE7: 41FFD3 CALL R11
; EEA: L0: 488BE5 MOV RSP, RBP
; EED: F8 CLC
; EEE: 5D POP RBP
; EEF: C3 RET
(struct: pt ([x : Real] [y : Real]))
(: distance (pt pt -> Real))
(define (distance p1 p2)
(sqrt (+ (sqr (- (pt-x p2) (pt-x p1)))
(sqr (- (pt-y p2) (pt-y p1)))))): operator seems a little un-lispy.
(declaim (ftype (function ((unsigned-byte 64)) (values (unsigned-byte 64) &optional))
shuffle))values form. I'm not sure what the rationale for the ftype is.ftype for the same reason as function elsewhere. You have to tell Lisp you're talking about the name in the function namespace, not the variable namespace.
CL-USER> (defun square (x)
(* x x))
SQUARE
CL-USER> (describe 'square)
COMMON-LISP-USER::SQUARE
[symbol]
SQUARE names a compiled function:
Lambda-list: (X)
Derived type: (FUNCTION (T) (VALUES NUMBER &OPTIONAL))
Source form:
(SB-INT:NAMED-LAMBDA SQUARE
(X)
(BLOCK SQUARE (* X X)))
; No value
CL-USER> (defun square (x)
(declare (type integer x))
(* x x))
STYLE-WARNING: redefining COMMON-LISP-USER::SQUARE in DEFUN
SQUARE
CL-USER> (describe 'square)
COMMON-LISP-USER::SQUARE
[symbol]
SQUARE names a compiled function:
Lambda-list: (X)
Derived type: (FUNCTION (INTEGER) (VALUES UNSIGNED-BYTE &OPTIONAL))
Source form:
(SB-INT:NAMED-LAMBDA SQUARE
(X)
(DECLARE (TYPE INTEGER X))
(BLOCK SQUARE (* X X)))(declare (type array float (100))). Now if you have declared a high enough optimize speed value and low enough safety value, your compiler will probably emit some very fast code.
(declaim (ftype (function ((simple-array single-float (1000))
(simple-array single-float (1000)))
(values (simple-array single-float (1000)) &optional))
silly-addition))
(defun silly-addition (array1 array2)
(let ((result (make-array 1000 :element-type 'single-float)))
(declare (type (simple-array single-float (1000)) result))
(dotimes (i 1000 result)
(declare (type fixnum i))
(setf (aref result i) (+ (the single-float (aref array1 i))
(the single-float (aref array2 i)))))))
CL-USER> (disassemble 'silly-addition)
; disassembly for SILLY-ADDITION
; Size: 151 bytes
; 055E7C62: B8D5000000 MOV EAX, 213 ; no-arg-parsing entry point
; 67: B9D0070000 MOV ECX, 2000
; 6C: BEE8030000 MOV ESI, 1000
; 71: 488D14B51F000000 LEA RDX, [RSI*4+31]
; 79: 4883E2F0 AND RDX, -16
; 7D: 49896C2440 MOV [R12+64], RBP
; 82: 4D8B5C2418 MOV R11, [R12+24]
; 87: 4C01DA ADD RDX, R11
; 8A: 4939542420 CMP [R12+32], RDX
; 8F: 7658 JBE L4
; 91: 4989542418 MOV [R12+24], RDX
; 96: 498BD3 MOV RDX, R11
; 99: L0: 488D520F LEA RDX, [RDX+15]
; 9D: 488942F1 MOV [RDX-15], RAX
; A1: 48894AF9 MOV [RDX-7], RCX
; A5: 49316C2440 XOR [R12+64], RBP
; AA: 7402 JEQ L1
; AC: CC09 BREAK 9 ; pending interrupt trap
; AE: L1: 31C9 XOR ECX, ECX
; B0: EB28 JMP L3
; B2: 660F1F840000000000 NOP
; BB: 0F1F440000 NOP
; C0: L2: F30F104C4B01 MOVSS XMM1, [RBX+RCX*2+1]
; C6: F30F10544F01 MOVSS XMM2, [RDI+RCX*2+1]
; CC: F30F58D1 ADDSS XMM2, XMM1
; D0: F30F11544A01 MOVSS [RDX+RCX*2+1], XMM2
; D6: 4883C102 ADD RCX, 2
; DA: L3: 4881F9D0070000 CMP RCX, 2000
; E1: 7CDD JL L2
; E3: 488BE5 MOV RSP, RBP
; E6: F8 CLC
; E7: 5D POP RBP
; E8: C3 RET
; E9: L4: 492B542418 SUB RDX, [R12+24]
; EE: 52 PUSH RDX
; EF: BA305B4200 MOV EDX, 4348720 ; alloc_tramp
; F4: FFD2 CALL RDX
; F6: 5A POP RDX
; F7: EBA0 JMP L0
CL-USER> (defparameter *a* (make-array 1000
:element-type 'single-float
:initial-contents
(loop for i from 0 below 1000
collect (random 1.0f0))))
;; Same for B
CL-USER> (time (dotimes (i 1000000) (silly-addition *a* *b*)))
Evaluation took:
1.750 seconds of real time
1.830000 seconds of total run time (1.830000 user, 0.000000 system)
[ Run times consist of 0.287 seconds GC time, and 1.543 seconds non-GC time. ]
104.57% CPU
4,671,423,259 processor cycles
4,015,683,312 bytes consed
(declaim (optimize (compilation-speed 0) (debug 0) (safety 0) (space 0) (speed 3))).macroexpand-1 and Lisp editors often have this bound to a button so e.g. I can C-RET on some macro in my source, and a new window will pop up with its expansion; then I can C-RET on other macros within that window, and so on till I get to where I need. Lisp implementations that also implement CLTL2 might provide macroexpand-all or your editor might provide something similar. Furthermore, the package system really helps with writing macros. If you write a macro in package foo, then if it uses a symbol barit is really using the symbol foo::bar, and in a package baz, it won't shadow or interfere with a symbol of the same name i.e. baz::bar (unless you exported bar, and baz imported it). There's also the high level hygeine abstractions with-gensyms and once-only available in e.g. Alexandria and described in many books.
(defun plus ((int a) (int b)) (+ a b))
(defun <NAME> ((type1 arg1) .. (typen argn)) (<BODY>))
defmethod is already like that :)