C, 59 바이트
i;f(char*s){while(*s&3?*s&9||(i+=i+*s%5):putchar(i),*s++);}
마법의 숫자, 어디서나 마법의 숫자!
(또한 C는 Python, JS, PHP 및 Ruby보다 짧습니까?
문자열을 입력으로 사용하여 STDOUT으로 출력하는 기능입니다.
연습
기본 구조는 다음과 같습니다.
i; // initialize an integer i to 0
f(char*s){
while(...); // run the stuff inside until it becomes 0
}
여기서 "내부 내용"은 ,*s++
쉼표 연산자가 두 번째 인수의 값만 반환하는 코드 묶음입니다 . 따라서 이것은 문자열을 통해 실행 *s
되며 ++
종료하기 전에 후행 NUL 바이트를 포함하여 모든 문자로 설정 됩니다 (postfix 는 이전 값을 반환하므로).
나머지를 살펴 보자.
*s&3?*s&9||(i+=i+*s%5):putchar(i)
삼항 및 단락을 벗겨 내면 ||
확장 할 수 있습니다.
if (*s & 3) {
if (!(*s & 9)) {
i += i + *s % 5;
}
} else {
putchar(i);
}
이 마법 번호는 어디에서 왔습니까? 다음은 관련된 모든 문자의 이진 표현입니다.
F 70 01000110
B 66 01000010
i 105 01101001
z 122 01111010
u 117 01110101
32 00100000
\0 0 00000000
먼저 공백과 NUL을 나머지 문자와 분리해야합니다. 이 알고리즘은 작동 방식에 따라 "현재"숫자의 누산기를 유지하고 공백이나 문자열 끝에 도달 할 때마다 인쇄합니다 (예 :) '\0'
. ' '
그리고 '\0'
2 개의 최하위 비트를 설정하지 않은 유일한 문자 라는 점을 인식 0b11
하여 문자가 공백이거나 NUL이면 0을 얻기 위해 비트 단위 AND 문자를 사용 하고 그렇지 않으면 0이 아닙니다 .
첫 번째 "if"브랜치에서 더 깊이 파고 들면 이제 우리는 하나의 문자를 갖게 FBizu
됩니다. F
s 및 B
s 의 누산기를 업데이트하기로 선택 했기 때문에 s를 필터링하는 방법이 필요했습니다 izu
. 편리하게, F
그리고 B
둘은 제 2, 제 3, 또는 설정 일곱째 최하위 비트를, 그리고 다른 모든 숫자는 적어도 하나 개의 다른 비트 세트를 갖는다. 실제로, 이들은 모두 첫 번째 또는 네 번째 최하위 비트를 갖습니다. 따라서, 우리는 비트 단위 수와 함께 0b00001001
, 9 인 0을 얻을 것이다 F
및 B
및 제로 그렇지.
우리는 우리가있는 것으로 확인되었습니다 후 F
또는 B
, 우리는 그들에게 매핑 할 수 0
및 1
때문에, 그 계수 5를 복용하여 각각을 F
하다 70
하고 B
있다 66
. 그런 다음 스 니펫
i += i + *s % 5;
그냥 골치 아픈 말이다
i = (i * 2) + (*s % 5);
이는 다음과 같이 표현 될 수도 있습니다
i = (i << 1) | (*s % 5);
최소 비트 위치에 새 비트를 삽입하고 다른 모든 비트를 1 이상 이동시킵니다.
"하지만 기다려!" 당신은 항의 할 수 있습니다. "인쇄 한 후 i
언제 다시 0으로 재설정됩니까?" 글쎄, putchar
인수를으로 캐스팅하면 unsigned char
크기는 8 비트가됩니다. 즉, 8 번째 최하위 비트 (즉, 이전 반복의 정크)를 지나친 모든 항목이 버려 지므로 걱정할 필요가 없습니다.
덕분에 @ETHproductions 대체하는 제안에 대한 57
로 9
, 바이트를 저장!