계수를 사용한 C 추가


81

를 인쇄하는 흥미로운 C 코드를 발견 A + B했지만 이해하는 데 어려움이 있습니다.

입력 형식 :

A B

여기서 A, B사이의 정수이다 010단일 공간으로 분리된다.

암호:

main( n )
{
    gets( &n );
    printf("%d", n % 85 - 43);
}

이것은 짧은 코딩을위한 것이므로 경고를 신경 쓰지 마십시오.

내가 지금까지 이해 한 것 :

gets( &n )A, 공백 및 B의 ASCII 값을의 하위 3 바이트에 저장 n합니다. 예를 들어, A = 3B = 8얻을 것이다 n = 0x00382033. 주어진 조건 n은 넘침을 방지 합니다. 그러나 나는 어떻게 n % 85 - 43산출 하는지 이해하지 못한다 A + B.

이 숫자를 어떻게 생각합니까?


2
참으로 흥미 롭습니다.
Havenard

12
힌트는 85가 이진수로 비트를 번갈아 가며 01010101. 이 접근 방식을 10101010, 즉 숫자 170으로 시도 하면 유사한 기능을 얻을 수 있습니다. 유일한 차이점은 0 0대신 숫자 128 ( 10000000이진수) 을 얻는다는 것 입니다. 유사한 기술이 0x55555555and 0xAAAAAAAA(0x55 = 85 및 0xAA = 170)와 같은 마스크를 사용하여 비트 세트의 비트 수를 계산하는 것과 같은 비트 연산으로 많은 최적화를 수행하는 데 사용됩니다 . 16 진수 코드를 검색하면 흥미로운 기사가 ​​많이 나옵니다.
Havenard

와우, 85 번에 이렇게 깊이를 기대 한 적이 없습니다. 통찰력을 가져 주셔서 감사합니다.
William Lee

1
0과 9 사이를 의미한다고 생각합니까?
파이프

1
그것은 확실히 ioccc 가치가 있습니다.
dgnuff

답변:


87

little-endian int (ASCII 텍스트, 8 비트 바이트 가정, 코드에 필요한 기타 모든 가정)를 사용하고 코드에서 기술적으로 잘못된 모든 C 항목을 무시하면 "내가 이해하는 내용 지금까지 "가 맞습니다.

gets(&n)A, 공백 및 B의 ASCII 값을의 처음 3 바이트에 저장 n합니다. 또한 4 번째 바이트에 null 종결자를 저장합니다. 이들의 바이트에 해당 ASCII 값 저장 n에 결과 n값을 가지고 B*256*256 + space*256 + A, 여기서 B, spaceA대응하는 ASCII 값을 나타낸다.

256 mod 85는 1이므로 모듈 식 산술의 속성에 따라

(B*256*256 + space*256 + A) % 85 = (B + space + A) % 85

덧붙여서, 4 바이트 big-endian int를 사용하면

(A*256*256*256 + space*256*256 + B*256) % 85 = (B + space + A) % 85

따라서 4 바이트 정수가있는 한 엔디안은 중요하지 않습니다. (더 큰 이하의 int 문제가 될 수있다, 예를 들어, 8 바이트의 int로, 우리의 바이트에 무엇에 대해 걱정할 필요가 것 ngets설정되지 않았다.)

공백은 ASCII 32이고 숫자 문자의 ASCII 값은 48 + 숫자 값입니다. (숫자 문자의 ASCII 값이 아니라) 입력 된 숫자의 숫자 값을 정의 a하고b

(B + space + A) % 85 = (b + 48 + 32 + a + 48) % 85
                     = (a + b + 128) % 85
                     = (a + b + 43) % 85

(B + space + A) % 85 - 43 = (a + b + 43) % 85 - 43
                          = (a + b) % 85
                          = a + b

마지막 두 동등성는 사실에 의존 곳 a과는 b0에서 9까지의 값을.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.