x86-64 기계 코드, 22 바이트
48 B8 41 92 34 6D DB F7 FF FF 83 F9 40 7D 03 48 D3 E8 83 E0 01 C3
위의 바이트는 64 비트 x86 기계 코드에서 입력 값이 Chicken McNugget 숫자인지 여부를 결정하는 함수를 정의합니다. 단일 양의 정수 매개 변수는 Windows에서 사용되는 Microsoft 64 비트 호출 규칙 에 따라 ECX
레지스터에 전달됩니다 . 결과는 레지스터에 반환 된 부울 값 입니다.EAX
ungolfed 어셈블리 니모닉 :
; bool IsMcNuggetNumber(int n)
; n is passed in ECX
movabs rax, 0xFFFFF7DB6D349241 ; load a 64-bit constant (the bit field)
cmp ecx, 64
jge TheEnd ; if input value >= 64, branch to end
shr rax, cl
TheEnd:
and eax, 1 ; mask off all but LSB
ret
분명히 이것은 Python에서 Anders Kaseorg의 솔루션에서 많은 부분을 차지 합니다. Chicken McNugget 숫자 값을 나타내는 비트 필드를 기반으로한다는 점입니다. 특히, 유효한 Chicken McNugget 번호에 해당하는이 필드의 각 비트는 1로 설정됩니다. 다른 모든 비트는 0으로 설정됩니다. (0은 유효한 Chicken McNugget 번호로 간주되지만, 마음에 들지 않으면 선호하는 설정은 단일 비트 수정입니다.)
먼저이 값을 레지스터에로드하여 시작합니다. 64 비트 값으로 이미 인코딩하는 데 8 바이트가 필요하고 1 바이트 REX.W 접두사가 필요하므로 바이트 단위로 실제로 소비되고 있지만 솔루션의 핵심입니다. 그만한 가치가 있다고 생각합니다.
그런 다음 입력 값만큼 필드를 오른쪽으로 이동합니다. * 마지막으로, 우리는 최하위 비트를 제외한 모든 것을 가려서 부울 결과가됩니다.
그러나 실제로 값에 포함 된 비트 수보다 많은 비트 수만큼 이동할 수 없으므로 0-63의 입력에 대해서만 작동합니다. 더 높은 입력 값을 지원하기 위해 입력 값의 맨 아래로 분기하는 함수의 상단에> = 64 인 테스트를 삽입합니다. 이것에 대해 흥미로운 점은 에서 비트 필드 상수를 미리로드RAX
한 다음 분기입니다 최하위 비트를 마스킹하는 명령까지 내려서 항상 1을 반환합니다.
온라인으로 사용해보십시오!
(C 함수 호출에는 GCC가 어셈블리 코드에서 사용하는 Microsoft 호출 규칙을 사용하여 호출하는 속성이 주석으로 표시됩니다. TIO가 MSVC를 제공 한 경우에는 필요하지 않습니다.)
__
* 시프트의 대안으로 x86 BT
명령어를 사용할 수 있었지만 인코딩하는 데 1 바이트 더 길어 졌으므로 이점이 없습니다. 우리는 한하지 않는 한 강제 편리에 입력 값을 통과하지 못한 다른 호출 규칙을 사용하는 ECX
레지스터. 소스 피연산자가 동적 시프트 카운트를 위해 SHR
필요 하기 때문에 이것은 문제가 될 CL
수 있습니다. 따라서 다른 호출 규칙 MOV
에 따라 전달 된 레지스터의 입력 값을 가져와야하므로 ECX
2 바이트가 필요합니다. 이 BT
명령어는 1 바이트의 비용으로 모든 레지스터를 소스 피연산자로 사용할 수 있습니다 . 따라서 그러한 상황에서는 바람직 할 것입니다.BT
해당 비트의 값을 캐리 플래그 (CF)에 넣습니다. 따라서 SETC
명령어를 사용하여 해당 값을 정수 레지스터에서 가져와 AL
호출자에게 반환 할 수 있습니다.
대체 구현, 23 바이트
다음은 모듈로 및 곱셈 연산을 사용하여 입력 값이 Chicken McNugget 수인지 확인하는 대체 구현입니다.
레지스터 의 입력 값을 전달 하는 System V AMD64 호출 규칙을 사용합니다 EDI
. 결과는 여전히 Boolean이며로 반환됩니다 EAX
.
그러나 위의 코드와 달리 이는 역의 부울입니다 (구현 편의상). 그것은 반환 false
입력 값이 치킨 McNugget 번호 인 경우, 또는 true
입력 값이있는 경우 없는 치킨 McNugget 번호.
; bool IsNotMcNuggetNumber(int n)
; n is passed in EDI
8D 04 3F lea eax, [rdi+rdi*1] ; multiply input by 2, and put result in EAX
83 FF 2B cmp edi, 43
7D 0E jge TheEnd ; everything >= 43 is a McNugget number
99 cdq ; zero EDX in only 1 byte
6A 03 push 3
59 pop rcx ; short way to put 3 in ECX for DIV
F7 F1 div ecx ; divide input value by 3
6B D2 14 imul edx, edx, 20 ; multiply remainder of division by 20
39 D7 cmp edi, edx
0F 9C C0 setl al ; AL = (original input) < (input % 3 * 20)
TheEnd:
C3 ret
추악한 점은 상단의 비교 및 분기로 입력 값> = 43을 명시 적으로 처리해야한다는 것입니다. 이 같은 분기 필요로하지 않는이 일을 다른 방법으로 분명하다 케어 드 coinheringaahing의 알고리즘은 , 그러나 이것은 걸릴 것이다 많은 그래서 합리적인 해결책이 아니라, 더 인코딩 할 바이트를. 비트 필드 자체를 인코딩하는 데 너무 많은 바이트가 있기 때문에 위의 비트 필드 기반 솔루션보다 더 우아하고 바이트 수가 적은 비트 트위들 링 트릭이 누락되었을 것으로 생각합니다. 잠시 동안 여전히 볼 수 없습니다.
아 글쎄, 온라인으로 시도 어쨌든!