현명하지 않은 비트 연산


16

나는 골프를 좋아 dc하지만 dc비트 단위 연산이 없기 때문에 때때로 좌절 합니다.

도전

하여 C의 비트 연산의 상당 구현 네라는 이름의 기능을 제공 &, |, ~^(비트 AND, OR, NOT 및 XOR을). 각 함수는 ~최소한 32 비트 부호없는 정수인 두 개의 피연산자를 사용합니다 ( 하나만 사용). 각 함수는 피연산자와 같은 비트 너비의 부호없는 정수를 반환합니다.

제한

에서 지원하는 작업 만 사용할 수 있습니다 dc. 이것들은:

  • + - * / 산술 덧셈, 뺄셈, 곱셈 및 나눗셈
  • ~ 모듈로 (또는 언어가 지원하는 경우 divmod)
  • ^ 지수화
  • | 모듈 식 지수
  • v 제곱근
  • > >= == != <= < 표준 평등 / 불평등 연산자
  • >> <<비트 시프트 연산자. dc이것들은 없지만 2의 제곱으로 나누기 / 곱하기 측면에서 사소하게 구현되었으므로 이것을 허용 할 것입니다.

dc(재귀) 매크로와 (평등) 평등 작업을 사용하여 서투르게 제어 구조를 구축합니다. 언어에 내장 된 제어 구조를 사용할 수 있습니다.

당신은 또한 논리 연산자를 사용할 수 있습니다 && || ! 이러한에서 직접 사용할 수없는 경우에도 불구하고 dc.

당신은 비트 단위 연산자를 사용해서는 안 & , |, ~^또는 사소을 구현하는 기능.

또한 기본 문자열 변환 연산자 또는 함수를 사용해서는 안됩니다.


답변을 확인하는 데 도움이되도록 테스트 프로그램 또는 온라인 컴파일러 스 니펫 (골프 점수에 포함되지 않음)을 제공하는 것도 고려하십시오.


원하는 연산을 매개 변수로 취하는 하나의 함수를 구현할 수 있습니까? 또한 비트 시프트를위한 ​​스탠드 인으로 2를 정수로 나눌 수 있습니까?
xnor

@xnor 네 개의 연산자 각각을 구현하는 4 개의 공용 함수를 제공해야합니다. 네 가지 공용 함수 모두에 의해 호출되는 공통 / 도우미 개인용 메소드 / 함수가있을 수 있지만, 모두 골프 스코어에 포함되어야합니다.
Digital Trauma

7
@xnor 당신과 당신은 또한 xnor 연산자를 구현해야합니다 ;-)
Digital Trauma

네 가지 익명 함수 목록을 생성 할 수 있습니까?
xnor

@MariaTidalTug 네 개의 함수 목록을 반환하고 하나를 수동으로 선택하여 적용하는 것 (xnor 제안한대로)과 선택 매개 변수를 받아들이고 선택을 수행하는 하나의 함수를 갖는 것 (wolfhammer가 대답 한 것)의 효과적인 차이점은 무엇입니까? 둘 다 코드 크기를 사용자 코드로 오프로드 할 때 네 개의 명명 된 함수가 있다는 점을 비슷하게 약화시키는 것 같습니다. 심지어 사용자 코드가 후자의 경우보다 더 복잡하기 때문에 전자가 더 훼손한다고 주장하기까지합니다.
Runer112

답변:


4

C, 134

C 프리 프로세서는 남용하기 매우 재미 있습니다. 기본적으로이 매크로 3 개 함수를 정의하고, a, o, 및 x에 대해 and, orxor각각. 이러한 연산에 대한 알고리즘의 유일한 차이점은 결과에서 비트를 설정하는 기준입니다.

not기능 n입니다.

#define f(n,c)n(a,b){for(r=0,i=31;i+1;--i)if(((a>>i)%2+(b>>i)%2)c)r+=1<<i;return r;}
i,r;n(a){return 0xffffffff-a;}f(a,/2)f(o,)f(x,%2)

테스터 프로그램 (오랜 시간이 걸렸지 만 전혀 최적화하는 데 시간을 들이지 않았지만 MAX_INT 관련 항목 외에도 가능한 모든 테스트 사례를 테스트합니다) :

#define m_assert(expected, condition, actual)\
    if(!((expected) condition (actual)))\
        printf("assert fail @ line %i, expected: %x, actual %x, condition "#condition"\n", __LINE__, expected, actual);

int main()  {
    unsigned int j,k;
    for(j=0; j<0xffff; ++j)    {
        m_assert(~j, ==, n(j));
        for(k=0; k<0xffff; ++k)    {
            m_assert(j & k, ==, a(j,k));
            m_assert(j | k, ==, o(j,k));
            m_assert(j ^ k, ==, x(j,k));
        }
    }

1
죄송합니다. 잊어 버렸습니다. 지금 고쳤습니다.
pseudonym117

4

ised 76 바이트

ised는 또한 비트 단위 연산을 가지고 있지 않습니다. 일반적으로 성가 시지만, 이제는 실제로 구현 해야 하기 때문에 환영 합니다.

기능은 번호가 매겨진 메모리 슬롯에 저장됩니다 (상세한 이름 없음).

이진과의 변환 :

@5{:x/2^[32]%2:};
@6{:x@:2^[32]:};

될 수는 @1{:$6::{1-$5::x}:}없지만 그냥 빼는 것이 더 쉽습니다.

@1{:2^32-x-1:};

또는:

@2{:$6::{$5::{x_0}:+$5::{x_1}>0}:};

과:

@3{:$6::{$5::{x_0}:*$5::{x_1}}:};

XOR :

@4{:$6::{$5::{x_0}:<>$5::{x_1}}:};

이것은 우리에게 156 바이트 (줄 바꿈 및 세미콜론 포함)를 가져올 것입니다. 테스트 코드는 다음과 같습니다 ($ 1, $ 2, $ 3, $ 4라는 이름으로 연속, NOT, OR, AND, XOR) :

> $1::{6}
4294967289
> $2::{12 11}
15
> $3::{12 11}
8
> $4::{12 11}
7

그러나 물론 OR과 NOT은 우리가 실제로 필요로하는 것이며 단순화 할 수 있습니다.

@1{:2^32-x-1:};
@2{:@+{2^U{?{$5::x}%32}}:};
@3{:${1 2 1}::x:};
@4{:$3::{$2::x${1 2}::x}:};
@5{:x/2^[32]%2:};

109 자입니다. 줄 바꿈과 세미콜론을 건너 뛰고 약간 더 골프를 치면 76자가됩니다.

@3{@1{:2^32-x-1:}@2{:@+{2^U{?{x/2^[32]%2}%32}}:}$1}@4{{:$2::x${1 2}::x:}$3};

1

(537) (490)

Nim 컴파일러 0.10.2

나는 nim을 배울 이유를 찾고 있었으므로 우리는 간다.

코드 골프의 경우 변수 매개 변수와 암시 적 수익을 활용했습니다. 설명서따라 변수 매개 변수 는 스택 효율성이 떨어집니다. 개인적으로, 나는 암시적인 반환을 읽기가 더 어려워 사소한 절차에서만 사용할 것이라고 생각합니다.

알고리즘은 간단합니다. NOT을 제외한 모든 연산에 대해 각 비트를 비교하여 예상 진리표와 수동으로 비교합니다. 출력 변수에서 필요에 따라 각 비트를 설정하십시오. Nim에서 결과는 암시 적 반환 값입니다.

notZero 프로 시저를 대신하여 두 개의 부울 조건을 선언하기 위해 내장 OR 및 AND를 사용할 수 있는지 확실하지 않았습니다.

proc s(x, y, b: var int)=
  x = x div 2
  y = y div 2
  b *= 2

proc n(x: var int): int =
  return -(x+1)

proc a(x, y: var int): int =
  var b = 1
  while x > 0 and y > 0:
    if (x mod 2  + y mod 2) == 2:
      result += b

    s(x,y,b)

proc o(x, y: var int): int =
  var b = 1
  while x + y > 0:
    if (x mod 2 + y mod 2) >= 1:
      result += b

    s(x,y,b)

proc r(x, y: var int): int =
  var b = 1
  while x + y > 0:
    if (x mod 2 + y mod 2) == 1:
      result += b

    s(x,y,b)

여전히 더 나은 방법을 찾고 있습니다 ...

다음은 squished 버전과 전체 테스트 하네스를 자신의 컴퓨터에서 실행하는 것입니다.
두 개의 입력을 실행하려면 테스트 사례 lite가 있습니다.


@MariaTidalTug 설명해 주셔서 감사합니다!
cory.todd

나는 그것을 재현 할 수 없습니다. 계산기가 기본 16 모드입니까?
cory.todd

나는 pseudonym117와 비슷한 테스트 장치를 추가했습니다.
cory.todd

1

CJam, 71 바이트

{:F;0{:R;2md@2md@+F~!2I#*R+}64fI\;\;}:B{"2-"B}:A{'!B}:O{0SB}:N{'(B}:X];

설명

"B : UInt64 UInt64 String -> UInt64
 Computes a bitwise operation on the two given unsigned integers. The operation
 is defined by the logical inverse of the result of evaluating the given string
 given the sum of two input bits.";
{
  :F;             "Save the operation string.";
  0               "Initialize the result to 0.";
  {               "For I from 0 through 63:";
    :R;             "Save the result.";
    2md@2md@        "Divide each input by 2 and collect the remainders as the
                     next pair of bits to process.";
    +F~!            "Compute the logical inverse of the result of evaluating
                     the operation string given the sum of the two bits.";
    2I#*            "Adjust the resulting bit to be in the correct output
                     position by multiplying it by 2^I.";
    R+              "Add the location-adjusted bit to the result.";
  }64fI
  \;\;            "Clean up.";
}:B

"A : UInt64 UInt64 -> UInt64
 Computes the bitwise AND of the two given unsigned integers.
 This is done by passing the inputs along to B with an operation such that:
   bit_out = !((bit_in_1 + bit_in_2) - 2)";
{"2-"B}:A

"O : UInt64 UInt64 -> UInt64
 Computes the bitwise OR of the two given unsigned integers.
 This is done by passing the inputs along to B with an operation such that:
   bit_out = !(!(bit_in_1 + bit_in_2))";
{'!B}:O

"N : UInt64 -> UInt64
 Computes the bitwise NOT of the given unsigned integer.
 This is done by passing the input and 0 along to B with an operation such that:
   bit_out = !((bit_in + 0))";
{0SB}:N

"X : UInt64 UInt64 -> UInt64
 Computes the bitwise XOR of the two given unsigned integers.
 This is done by passing the inputs along to B with an operation such that:
   bit_out = !((bit_in_1 + bit_in_2) - 1)";
{'(B}:X

];              "Clean up.";

테스트 스위트

이 코드는 균일하게 분포 된 64 비트 부호없는 입력을 사용하여 각각의 my 및 / 또는 not 및 xor 함수의 실행을 100 번 테스트하고 결과를 내장 연산자가 생성 한 결과와 비교합니다. 평가 연산자를 무의식적으로 사용하기 때문에 온라인 인터프리터에서 속도가 느리고 약 1 분 정도 걸릴 수 있습니다. 그러나 모든 것이 제대로 진행되면 발견 된 불일치가 인쇄되므로 실행이 출력없이 끝나야합니다.

N:L;
{:F;0{:R;2md@2md@+F~!2I#*R+}64fI\;\;}:B{"2-"B}:A{'!B}:O{0SB}:N{'(B}:X];
{;Y32#__mr*\mr+}2e2%2/{~:U;:V;"A&O|X^"2/{[{US@SV" = "UV5$~L}/9$2$={];}{]oLo}?}/"N~"[{U" = "U3$~Y64#(&L}/6$2$={];}{]oLo}?}/

0

자바 스크립트 294 267

@AlexA.와 @kennytm의 제안으로 몇 바이트를 더 줄일 수있었습니다.

기능 :

B=(n,m,t)=>{for(var p=4294967296,y=0;p>=1;p/=2)y+=t=='x'&&(n>=p||m>=p)&& !(n>=p&&m>=p)?p:0,y+=t=='a'&&n>=p&&m>=p?p:0,y+=t=='o'&&(n>=p||m>=p)?p:0,n-=n>=p?p:0,m-=m>=p?p:0
return y}
N=(n)=>{return 4294967295-n}
A=(n,m)=>B(n,m,'a')
O=(n,m)=>B(n,m,'o')
X=(n,m)=>B(n,m,'x')

예:

var n = 300;
var m = 256;
console.log(X(n,m) + ", " + (n ^ m));
console.log(O(n,m) + ", " + (n | m));
console.log(A(n,m) + ", " + (n & m));
console.log(N(n) + ", " + (~n>>>0));
console.log(N(m) + ", " + (~m>>>0));

산출:

44, 44
300, 300
256, 256
4294966995, 4294966995
4294967039, 4294967039

2
AND, OR에 각각 하나씩 4 가지 공용 함수를 제공해야합니다. NOT과 XOR. (네 개의 공용 함수 모두에 의해 호출되는 공통 / 도우미 개인용 메소드 / 함수가있을 수도 있습니다). 또한, 당신은 NOT을 잃어 버렸을 것입니다 – 아마도 가장 쉬운 방법 일 것입니다
Digital Trauma

감사합니다 @AlexA. 바이트를 추가하고 더 골프를 쳤다.
wolfhammer

당신은 뒤에 공간을 잃을 수 for및 교체 function B(n,m,t)와 함께 B=(n,m,t)=>. 다른 기능도 마찬가지입니다.
Alex A.

4*(1<<30)4294967296과 4294967295에 사용할 수 있습니다. -1>>>0var여기에 정말로 필요한가? ③ (n,m)=>B(n,m,'a')대신 쓸 수 있음(n,m)=>{return B(n,m,'a')}
kennytm
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.