セカンドゼロを見つける


10

チャレンジ

32ビットの2の補数形式整数を指定して、バイナリ表現の2番目の最下位ゼロ桁のインデックスを返します。のインデックスは0最下位ビットを31表し、のインデックスは最上位ビットを表します。

2番目のゼロがない場合は、0、負の数、偽の値を返すか、言語で意味のある方法でエラーを報告することができます。

必要に応じて1インデックスを使用できますが、以下のテストケースでは0インデックスを使用します。

必要に応じて、符号なし整数を使用できます。その場合、範囲内の整数を処理する必要があります[0, 2^32)。符号付き整数を使用する場合は、範囲内の整数を処理する必要があります[-2^31, 2^31)。ここでのテストケースは符号付き整数を使用しますが、(符号付き)-x2^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 2017

1
整数または文字列0b...を入力として使用していますか?
TheLethalCoder 2017

1
@JonathanAllan私はそうは思いません、私はジェリーの答えで修正された2^32-1ので、私は戻るべきではなかったから33です。
Erik the Outgolfer 2017

1
@JonathanAllan Erikの答えは正しいです。私はあなたが符号付きまたは符号なしとしてそれらを取ることを選択するかどうかを32ビット整数を扱う必要があることを反映するために、チャレンジ仕様を更新しました
musicman523

回答:


16

Python 2、45バイト

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

オンラインでお試しください!

0インデックス、符号なしの数値を使用し、2番目のゼロがない場合はエラーをスローします。

設定されていないビットのインデックスのリストを最低から最高まで作成し、2番目のエントリを返します。


5
PPCGへようこそ!素敵な最初の投稿!
Erik the Outgolfer 2017

ありがとう!私はまだPythonのゴルフのトリックに慣れていないので、このコードがすぐにゴルフに使えなかったことを嬉しく思います。
アーノルドパーマー

素晴らしい:) n = 2147483647はどうですか?
mdahmoune 2017

@mdahmoune 2 ** 31-1は、32ビットのバイナリ表現が0b01111111111111111111111111111111であり、2番目の0がないため、エラーになるはずです。何か欠落していない限り
Arnold Palmer

6

JavaScript(ES6)、34バイト

0ベースのインデックス、または-12番目のゼロが見つからない場合に返します。

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

テストケース

代替表現

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

再帰バージョン、42バイト

0ベースのインデックス、またはfalse2番目のゼロが見つからない場合に返します。

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ベースのインデックスを返すか、2番目のゼロが見つからない場合は、多くの再帰エラーをスローします

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

オンラインでお試しください!

2番目のゼロがない場合、範囲[1,31]にないものを出力します。これには32 33およびが含まれ(-inf+nanj)ます。それは理にかなっていると思います。

計算しlog(((x|(x+1))+1)&~x)/log(2)ます。


1
-inf+nanj私はそれが存在することさえできるとは思いませんでした
Luis Mendo 2017

31 1のバイナリ表現を持つ(-inf+nanj)入力に対しては出力されないため、214748364732ビットの符号付き表記では2番目のゼロはありません(これが、私のものおよびErikの回答よりもはるかに短い理由です)。
ジョナサンアラン

実際には、ときそれが生み出しますか(-inf+nanj)
ジョナサンアラン

...ああ、うまくいったと思いますが、署名済みオプションを使用していますか?
ジョナサンアラン

4

Javaの、... 194 191 186のバイト

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バイトより小さな変数名を使用し
空白を削除するために-25バイト、さらに短い変数を取り、@ KevinCruijssenのヒントにより
-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;|代わりに||、括弧なし); bsbsaなどはすべて1文字にすることができます(コードゴルフでマルチバイトの変数/メソッド名を使用しないでください)。次のintようにを組み合わせることができますint o=2^32-2,c=0,i=x.length,l=i-1;。そして、ゴルフにはまだまだあります。Javaでゴルフをするためのヒント、すべての言語でのゴルフのためのヒントを読んでも面白いかもしれません。再び歓迎し、あなたの滞在をお楽しみください!:)
Kevin Cruijssen 2017

変数宣言で削除できるスペースがまだいくつかあると思います。ようこそ!:)
musicman523 2017

@ musicman523ありがとう、ええそれを修正しました。今のところ194 :)
0x45 '18

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 2017

1
@ 0x45 @KevinCruijssenのコードを変更すれば機能するfor(;j<2&i>0;j+=c[--i]==48?1:0);はずです。エラーはi文字列の長さに起因するため、最初は配列の境界を超えてインデックスを作成しようとしています。(更新されたスニペットに示されているように)前減分を行うと、最初にそれを使用したときc[c.length-1]に、元のコードのようにアクセスできます。
アーノルドパーマー


3

IA-32マシンコード、14 13バイト

Hexdump:

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を返します。

まず、入力を反転するため、ビットスキャン命令を使用して、設定されたビットを探すことができます。最下位セットビットを探してリセットし、最下位セットビットをもう一度探して、結果を返します。

ビットスキャン命令でセットビットが見つからない場合、Intelのドキュメントには出力が未定義であると記載されています。ただし、実際には、この場合、すべてのプロセッサは宛先レジスタを変更しません(Cody Grayが指摘したように、AMDのドキュメントではこの動作が必須であると説明されています)。

したがって、以下のケースがあります。

  1. ゼロビットなし(バイナリ111 ... 1):ecxは0に設定され、0のnotままです
  2. 1つのゼロビット:によってecxは0に設定されbtr、その後も0のままです。bsf
  3. 2つのゼロビット:ecxは適切な値に設定されます。 bsf

0のビットスキャンが未定義であると言うのはIntelのドキュメントのみです。AMDのドキュメントには、宛先が変更されていないことが明示的に記載されています。この動作を回避したい場合は、通常、REPプレフィックスを追加してLZCNTまたはTZCNTのいずれかを取得しますが、バイトカウントが増加するため、コードゴルフでは当然望ましくありません。
コーディグレイ

1
あなたは実際にここで多くの仕事をしています。このチャレンジでは、ゼロビットがない場合とゼロビットが1つしかない場合を区別する必要はありません。どちらの場合も、0(または負の値)を返すことができます。したがって、1バイトのSALC+ DEC非常に賢いですがECX、2番目のBSF命令の時点にあるものを使用するだけで、バイトを削ることができます。必要なのはXCHG、結果をEAX返すために結果を取得するための1バイトだけです。言い換えれば、not ecx; bsf eax, ecx; btr ecx, eax; bsf ecx, ecx; xchg eax, ecx; ret
コディ・グレイ

1
上記の「オンラインで試す」リンクは次のとおりです。ECX入力レジスタとして使用しているので、GCCにfastcall呼び出し規約を使用するように指示する必要があります。
コーディグレイ

2

Dyalog APL、20バイト

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

1インデックスを使用しINDEX ERROR、2番目のゼロがない場合にスローします。

どうやって?

⍵⊤⍨- としてエンコード

32⍴2 -長さ32のバイナリ文字列

-逆

~ -否定(0→1、1→0)

(⍳32)/⍨ -1〜32の範囲で圧縮する(インデックスを0のままにする)

2⊃ -2番目の要素を選択


Where()を使用して大量のバイトを節約できます
TwiNight

@TwiNightは、dyalog 14を使用します
ウリエル

TIOには、必要に応じてDyalog 16があります
TwiNight


1

ゼリー、12 バイト

,4BUFḣ32¬TḊḢ

整数を取り、unsignedオプションを使用して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)ビットを操作できるようにする命令の1つを使用することになります、のようなBSFBSRPOPCNTBT、などAnatolygはいるこれらの線に沿って解決策を提出しました。勝てるかどうかはまだ決まっていません。:-p
コーディグレイ

1
ちなみに、レジスターを-1に設定するのに役立つ可能性のあるコードゴルフトリックは、それを-1とORすることです。たとえば、or ecx, -1。これは3バイトで、XOR + NEGより1バイト短いです。これは、デスティネーションレジスタに誤った読み取り依存関係を導入するため、ゴルフをしていないとき良いトリックではありませんが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.