두 번째 영점 찾기


10

도전

32 비트 2의 보수 형식 정수가 제공 되면 이진 표현에서 두 번째 로 중요도가 낮은 두 번째 0 의 인덱스를 반환합니다 . 여기서 인덱스 는 가장 중요하지 않은 비트 031나타내고 인덱스 는 가장 중요한 비트 를 나타냅니다.

두 번째 0이 없으면 0, 음수, 잘못된 값을 반환하거나 사용자 언어에 맞는 방식으로 오류를보고 할 수 있습니다.

원하는 경우 1 인덱싱을 사용할 수 있지만 아래 테스트 사례는 0 인덱싱을 사용합니다.

원하는 경우 부호없는 정수를 사용할 수 있습니다. 그렇게하면 범위의 정수를 처리해야합니다 [0, 2^32). 부호있는 정수를 사용하는 경우 범위의 정수를 처리해야합니다 [-2^31, 2^31). 여기서 테스트 사례는 부호있는 정수를 사용하지만 -x(서명)은 2^32 - x(부호 없음)입니다.

테스트 사례

0 (0b00)-> 1
1 (0b001)-> 2
10 (0b1010)-> 2
11 (0b01011)-> 4
12 (0b1100)-> 1
23 (0b010111)-> 5
-1 (0b11..11)-> 없음
-2 (0b11..10)-> 없음
-4 (0b11..00)-> 1
-5 (0b11..1011)-> 없음
-9 (0b11..10111)-> 없음
2 ^ 31-2 (0b0111..1110)-> 31

채점

이것은 이므로 각 언어에서 가장 짧은 답변이 이깁니다!


대신 부호없는 정수를 사용할 수 있습니까?
Leaky Nun

예, 범위에서 정수를 처리하는 한 가능합니다 [0, 2^32).
musicman523

1
정수 또는 문자열 0b...을 입력으로 사용합니까?
TheLethalCoder

1
@JonathanAllan 나는 2^32-1반환하지 않아야했기 때문에 젤리 답변을 수정 했기 때문에 그렇지 않은 것 같습니다 33.
Outgolfer Erik

1
@JonathanAllan Erik의 답변이 정확합니다. 32 비트 정수를 부호가 있거나 부호가없는 것으로 선택하든 상관없이 처리해야한다는 점을 반영하도록 챌린지 사양을 업데이트했습니다.
musicman523

답변:


16

파이썬 2 , 45 바이트

lambda n:[i for i in range(32)if n|1<<i>n][1]

온라인으로 사용해보십시오!

0 인덱싱, 부호없는 숫자를 사용하고 0 초에 오류가 발생합니다.

비 설정 비트의 인덱스 목록을 가장 낮은 값에서 가장 높은 값으로 만들고 두 번째 항목을 반환합니다.


5
PPCG에 오신 것을 환영합니다! 좋은 첫 게시물!
Outgolfer Erik

감사! 나는 아직도 파이썬에서 골프 속임수를 처음 접했기 때문에이 코드가 즉시 골치 아프게되어 기쁘다.
Arnold Palmer

위대한 :) n = 2147483647은 어떻습니까?
mdahmoune

@mdahmoune 2 ** 31-1은 32 비트의 이진 표현이 0b01111111111111111111111111111111이므로 0이 없습니다. 오류가없는 한 ...
Arnold Palmer

6

자바 스크립트 (ES6), 34 바이트

0부터 시작하거나 -1두 번째 0이없는 경우 인덱스를 반환합니다 .

n=>31-Math.clz32((n=~n^~n&-~n)&-n)

테스트 사례

대체 표현

n=>31-Math.clz32((n=~n^++n&-n)&-n)

재귀 버전, 42 바이트

0부터 시작하거나 false두 번째 0이없는 경우 인덱스를 반환합니다 .

f=(n,p=k=0)=>n&1||!k++?p<32&&f(n>>1,p+1):p

어떻게?

f=(n,p=k=0)=>                               // given n, p, k
             n&1||                          // if the least significant bit of n is set
                  !k++?                     // or this is the 1st zero (k was not set):
                       p<31&&               //   return false if p is >= 31
                             f(n>>1,p+1)    //   or do a recursive call with n>>1 / p+1
                                        :p  // else: return p

테스트 사례

Neil이 제안한 대체 버전, 41 바이트

0부터 시작하는 인덱스를 반환하거나 두 번째 0이 없으면 너무 많은 재귀 오류가 발생합니다.

f=(n,c=1)=>n%2?1+f(~-n/2,c):c&&1+f(n/2,0)

41 바이트 재귀 버전 :f=(n,c=1)=>n%2?1+f(~-n/2,c):c&&1+f(n/2,0)
Neil

5

젤리 , 7 바이트

|‘‘&~l2

온라인으로 사용해보십시오!

두 번째 0이 없으면 [1,31] 범위에없는 것을 출력합니다. 여기에는 32 33(-inf+nanj). 나는 그것이 의미가 있다고 생각합니다.

계산 log(((x|(x+1))+1)&~x)/log(2)합니다.


1
-inf+nanj나는 그것이 존재할 수도 있다고 생각하지 못했습니다
Luis Mendo

31 1의 이진 표현 (-inf+nanj)을 가진 입력에 대해서는 출력하지 않으므로 214748364732 비트 부호 표기법에서 두 번째 0은 없습니다 (이것이 내 것과 Erik의 대답보다 훨씬 짧은 이유입니다).
Jonathan Allan

사실, 때 않는 그것은 생산 (-inf+nanj)?
Jonathan Allan

... 아 나는 그것을 해결했다고 생각합니다. 서명 된 옵션을 사용하고 있습니까?
Jonathan Allan

4

Java, ... 194191186 바이트

static int f(int n){char[] c=Integer.toBinaryString(n).toCharArray();int j=0,o=2^32-2,i=c.length,l=i-1;if(n<0|n>o)return 0;for(;j<2&i>0;j+=c[--i]==48?1:0);if(j==2)return l-i;return 0;}

-159 바이트 작은 변수 명을 사용하여 여백 제거
@KevinCruijssen 팁 심지어 짧은 변수 감사 복용 후, -25 바이트
-18 바이트 이상의 공백, 함수명
단축 -3 바이트 @KevinCruijssen 덕분에, 실행 조건
-5 바이트 , @Arnold Palmer, @KevinCruijssen 덕분에 루프 단축

언 골프

public static int getPosSecondZero2(int number){
    int overflow = 2^32-2;
    if(number < 0 || number > overflow){
        return 0;
    }    
    String binaryString = Integer.toBinaryString(number);   
    char[] binaryCharArray = binaryString.toCharArray();    
    int count = 0;
    int idx = binaryCharArray.length;
    int length = binaryCharArray.length -1;
    while(count < 2 && idx>0){
        idx--;
        if(binaryCharArray[idx] == '0'){
            count++;
        }   
    }
    if(count == 2)
        return length-idx;
    return 0;
}

PPCG에 오신 것을 환영합니다! 골프를 할 수있는 것들이 꽤 있습니다 : static 제거 할 수 있습니다; if(n<0||n>o){return 0;}일 수있다 if(n<0|n>o)return 0;( |대신 ||없이 브래킷); bs, bsa등은 모두 단일 문자 일 수 있습니다 (코드 골프에서 멀티 바이트 변수 / 방법 이름을 사용하지 마십시오). 을 다음 int과 같이 결합 할 수 있습니다 int o=2^32-2,c=0,i=x.length,l=i-1;. 그리고 골프에 더 많은 것들이 있습니다. 자바로 골프를하기위한 팁모든 언어로 골프를하기위한 팁 을 읽는 것이 흥미로울 수 있습니다. 다시 한 번 환영하며 즐거운 시간을 보내십시오! :)
Kevin Cruijssen

변수 선언에서 제거 할 수있는 공백이 여전히 있다고 생각합니다. 어서 오십시오! :)
musicman523

@ musicman523 감사합니다. 수정했습니다. 194 for now :)
0x45

1
if(c[i]=='0'){j++;}여전히 if(c[i]==48)j++;-3 바이트 로 골프를 칠 수 있습니다 :) 편집 : 또는 더 나은 : -8 바이트 while(j<2&&i>0){i--;if(c[i]=='0'){j++;}}가 될 수 있습니다 for(;j<2&i>0;j+=c[i--]==48?1:0);.
Kevin Cruijssen

1
@ 0x45 @KevinCruijssen의 코드를 변경 for(;j<2&i>0;j+=c[--i]==48?1:0);하면 작동해야한다고 생각합니다. 오류는 i문자열의 길이 에서 발생 하므로 처음에는 배열의 경계를지나 색인을 작성하려고합니다. 업데이트 된 스 니펫에 표시된대로 사전 감소를 수행하면 처음 사용하는 경우 c[c.length-1]원래 코드와 같이 액세스 합니다.
Arnold Palmer


3

IA-32 기계 코드, 14 13 바이트

16 진 덤프 :

F7 D1 0F BC C1 0F B3 C1 0F BC C9 91 C3

분해 목록 :

0:  f7 d1                   not    ecx
2:  0f bc c1                bsf    eax,ecx
5:  0f b3 c1                btr    ecx,eax
8:  0f bc c1                bsf    ecx,ecx
b:  91                      xchg   eax, ecx
c:  c3                      ret

ecx; 에서 입력을받습니다 . 출력은입니다 al. 오류가 발생하면 0을 반환합니다.

우선, 입력을 반전시켜 비트 스캔 명령을 사용하여 설정된 비트를 찾을 수 있습니다. 최하위 세트 비트를 찾아서 재설정하고 최하위 세트 비트를 다시 찾고 결과를 반환합니다.

비트 스캔 명령이 설정된 비트를 찾지 못하면 인텔 설명서에 출력이 정의되어 있지 않다고 나와 있습니다. 그러나 실제로 모든 프로세서는이 경우 대상 레지스터를 변경하지 않은 채로 둡니다 (Cody Gray에서 언급 한 것처럼 AMD 설명서에서는이 동작을 필수로 설명합니다).

따라서 다음과 같은 경우가 있습니다.

  1. 0 비트 없음 (이진 111 ... 1) : ecx는 0으로 설정되고 0으로 not유지됩니다.
  2. 하나의 0 비트 : ecx는 0으로 설정되고 btr이후에도 0으로 유지됩니다.bsf
  3. 두 개의 0 비트 : ecx는 다음과 같이 적절한 값으로 설정됩니다. bsf

0의 비트 스캔이 정의되지 않았다는 것은 인텔의 문서 일뿐입니다. AMD의 문서는 목적지가 변경되지 않았다는 것을 명시 적으로 문서화합니다. 이 동작을 피하려면 일반적으로 LZCNT 또는 TZCNT를 얻기 위해 REP 접두사를 추가하지만 바이트 카운트가 증가하므로 코드 골프에는 바람직하지 않습니다.
코디 그레이

1
실제로 여기서 너무 많은 일을하고 있습니다. 이 문제는 0 비트가없는 경우와 1 비트가없는 경우를 구별 할 필요가 없습니다. 두 경우 모두 0 (또는 음수 값)을 반환 할 수 있습니다. 따라서 1 바이트 SALC+ DEC매우 영리 ECX하지만 두 번째 BSF명령 의 내용을 사용하여 바이트를 줄일 수 있습니다 . 필요한 유일한 XCHG결과는 결과를 얻기 위해 1 바이트 EAX이므로 반환 할 수 있습니다. 다시 말해not ecx; bsf eax, ecx; btr ecx, eax; bsf ecx, ecx; xchg eax, ecx; ret
Cody Grey

1
위의 "온라인으로 시도"링크는 다음과 같습니다 . 당신이 사용하고 있기 때문에 ECX입력 레지스터로, 우리는 fastcall 호출 규칙을 사용하여 GCC를 알 필요가있다.
코디 그레이

2

Dyalog APL, 20 바이트

{2⊃(⍳32)/⍨~⌽⍵⊤⍨32⍴2}

1- 인덱싱을 사용하고 INDEX ERROR두 번째 0이없는 경우 발생합니다.

어떻게?

⍵⊤⍨- 인코딩 A와

32⍴2 -길이가 32 인 이진 문자열

- 역전

~ -부정 (0 → 1, 1 → 0)

(⍳32)/⍨ -1-32 범위로 압축 (인덱스 0)

2⊃ -두 번째 요소를 선택하십시오


Where ( )를 사용하여 많은 바이트를 절약 할 수 있습니다.
TwiNight

@TwiNight 나는 dyalog 14를 사용합니다
Uriel

필요한 경우 TIO에 Dyalog 16이 있습니다
TwiNight


1

젤리 , 12 바이트

,4BUFḣ32¬TḊḢ

부호없는 옵션을 사용하고 1- 인덱싱 된 결과를 반환하는 정수 링크 (없는 경우 0을 반환).

온라인으로 사용해보십시오!

또는

32Ḷ2*|€n⁸TḊḢ

시도 해봐

어떻게?

1.

,4BUFḣ32¬TḊḢ - Link: number, n   e.g. 14
,4           - pair with 4            [14,4]
  B          - to binary              [[1,1,1,0],[1,0,0]]
   U         - upend                  [[0,1,1,1],[0,0,1]]
    F        - flatten                [0,1,1,1,0,0,1]
     ḣ32     - head to 32             [0,1,1,1,0,0,1] (truncates the right if need be)
        ¬    - not (vectorises)       [1,0,0,0,1,1,0]
         T   - truthy indexes         [1,5,6]
          Ḋ  - dequeue                [5,6]
           Ḣ - head                   5
             -   if the dequeued list is empty the head yields 0

2.

32Ḷ2*|€n⁸TḊḢ - Link: number, n   e.g. 14
32Ḷ          - lowered range of 32    [ 0, 1, 2, 3, 4, 5, ...,31]
   2*        - 2 exponentiated        [ 1, 2, 4, 8,16,32, ...,2147483648]
     |€      - bitwise or for €ach    [15,14,14,14,30,46, ...,2147483662]
        ⁸    - chain's right argument 14
       n     - not equal?             [ 1, 0, 0, 0, 1, 1, ..., 1]
         T   - truthy indexes         [ 1, 5, 6, ..., 32]
          Ḋ  - dequeue                [ 5, 6, ..., 32]
           Ḣ - head                   5
             -   if the dequeued list is empty the head yields 0

1

x86_64 기계 코드, 34 32 바이트

이것이 올바른 접근 방법인지 확실하지 않으면 많은 바이트가 있습니다 ( 그렇지 않음 ).

31 c0 83 c9 ff 89 fa 83 e2 01 83 f2 01 01 d1 7f 09 ff c0 d1 ef eb ee 83 c8 ff 83 f8 1f 7f f8 c3

온라인으로 사용해보십시오!

second_zero:
  # Set eax = 0
  xor  %eax, %eax
  # Set ecx = -1
  xor %ecx,%ecx
  not %ecx

  # Loop over all bits
Loop:
  # Get current bit
  mov %edi, %edx
  and $0x1, %edx
  # Check if it's zero and possibly increment ecx
  xor $0x1, %edx
  add %edx, %ecx
  # If ecx > 0: we found the position & return
  jg Return
  # Increment the position
  inc %eax
  # Shift the input and loop
  shr %edi
  jmp Loop

Fix:
  # If there's not two 0, set value to -1
  xor %eax,%eax
  not %eax

Return:
  # Nasty fix: if position > 31 (e.g for -1 == 0b11..11)
  cmp $31, %eax
  jg  Fix

  ret

-2바이트 @CodyGray 감사 합니다.


1
모든 비트를 통한 루핑은 아마도 코드 골프 나 실제 세계에 대한 올바른 접근법이 아닐 것입니다. 진정한 혁신은 한 번에 모든 32 (또는 64) 비트를 조작 할 수 있도록 지침 중 하나를 사용하는 것 같은 BSF, BSR, POPCNT, BT, 등 Anatolyg이있다 이러한 라인을 따라 솔루션을 제출 . 이길 수 있는지 아직 결정하지 못했습니다. :-p
코디 그레이

1
그건 그렇고, 레지스터를 -1로 설정하는 잠재적으로 유용한 코드 골프 트릭은 -1로 OR하는 것입니다. 예를 들면 다음과 같습니다 or ecx, -1. XOR + NEG보다 1 바이트 짧은 3 바이트입니다. 이것은 좋은 트릭없는 되지 는 대상 레지스터에 잘못된 읽기 의존성을 소개하기 때문에 골프,하지만 당신은 그냥 사용하는 것 mov ecx, -1과 5 바이트를 보낸다.
코디 그레이

1

8 , 149 바이트

2 base swap >s nip decimal s:len 32 swap n:- ( "0" s:<+ ) swap times s:rev null s:/ a:new swap ( "0" s:= if a:push else drop then ) a:each swap 1 a:@

주석이 달린 코드

: f \ n -- a1 a2 n 

  \ decimal to binary conversion
  2 base swap >s nip decimal     

  \ 32bit formatting (padding with 0)            
  s:len 32 swap n:- ( "0" s:<+ ) swap times  

  \ put reversed binary number into an array 
  s:rev null s:/

  \ build a new array with position of each zero 
  a:new swap ( "0" s:= if a:push else drop then ) a:each

  \ put on TOS the position of the 2nd least least-significant zero digit
  swap 1 a:@
;

사용법과 산출

ok> : f 2 base swap >s nip decimal s:len 32 swap n:- ( "0" s:<+ ) swap times s:rev null s:/ a:new swap ( "0" s:= if a:push else drop then ) a:each swap 1 a:@ ;

ok> [0, 1, 10, 11, 12, 23, -1, -2, -4, -5, -9, 2147483646]

ok> ( dup . " -> " .  f . 2drop cr ) a:each
0 -> 1
1 -> 2
10 -> 2
11 -> 4
12 -> 1
23 -> 5
-1 -> null
-2 -> null
-4 -> 1
-5 -> null
-9 -> null
2147483646 -> 31

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