64ビット整数の先行ゼロの数を見つける


18

問題:

64ビット符号付き整数の先行ゼロの数を見つける

ルール:

  • 入力を文字列として扱うことはできません。算術演算とビット演算がアルゴリズムを駆動するものであれば何でもかまいません
  • 出力は、言語に関係なく、数値の64ビット符号付き整数表現に対して検証する必要があります
  • デフォルトコードのゴルフ規則が適用されます
  • バイト単位の最短コードが勝つ

テストケース:

これらのテストでは、2の補数の符号付き整数を想定しています。言語/ソリューションに符号付き整数の異なる表現がないか、使用していない場合は、それを呼び出して、関連する可能性のある追加のテストケースを提供してください。倍精度に対処するいくつかのテストケースを含めましたが、リストすべきその他のテストケースをお気軽にご提案ください。

input                output   64-bit binary representation of input (2's complement)
-1                   0        1111111111111111111111111111111111111111111111111111111111111111
-9223372036854775808 0        1000000000000000000000000000000000000000000000000000000000000000
9223372036854775807  1        0111111111111111111111111111111111111111111111111111111111111111
4611686018427387903  2        0011111111111111111111111111111111111111111111111111111111111111
1224979098644774911  3        0001000011111111111111111111111111111111111111111111111111111111
9007199254740992     10       0000000000100000000000000000000000000000000000000000000000000000
4503599627370496     11       0000000000010000000000000000000000000000000000000000000000000000
4503599627370495     12       0000000000001111111111111111111111111111111111111111111111111111
2147483648           32       0000000000000000000000000000000010000000000000000000000000000000
2147483647           33       0000000000000000000000000000000001111111111111111111111111111111
2                    62       0000000000000000000000000000000000000000000000000000000000000010
1                    63       0000000000000000000000000000000000000000000000000000000000000001
0                    64       0000000000000000000000000000000000000000000000000000000000000000

13
PPCGへようこそ!「入力を文字列として扱うことができない」の背後にある理由は何ですか?これは、64ビット整数を処理できないすべての言語を失格にし、整数を使用するより多くの回答につながる可能性は低いです。
アーナルド

1
False代わりに戻ることができます0か?
ジョーキング

4
@Arnauldここと他のサイトには、文字列ベースのソリューションを具体的に要求する同様の質問が既にありますが、数学と論理演算に質問を開くものはありません。私の希望は、他の場所でまだ答えられていないこの問題に対するさまざまなアプローチを見ることです。これは文字列ソリューションにも開かれ、包括的なものになりますか?
デイブ

4
x86やARMなどのいくつかのCPUには、このための特定の命令があります(x86には実際にいくつかあります)。今日、ほとんどのプログラミング言語ではアセンブリ命令を呼び出すことができないため、なぜプログラミング言語がこの機能を公開しないのかといつも不思議に思っていました。
スリーブマン

1
@ user202729私はこれを不十分に言いましたと思う: '出力は、言語に関係なく、数値の64ビット符号付き整数表現に対して検証されるべきです'つまり、この質問はゼロの数をゼロの数として定義するということです64ビットの符号付き整数。符号付き整数と符号なし整数を排除するために、この制約を作成したと思います。
デイブ

回答:


41

Linux上のx86_64マシン言語、6バイト

0:       f3 48 0f bd c7          lzcnt  %rdi,%rax
5:       c3                      ret

HaswellまたはK10以上のプロセッサとlzcnt命令が必要です。

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



1
私は(あなたがLinux上で言ったのだが)使わ呼び出し規約を指定することをお勧めします
QWR

@qwrパラメーターは%rdiで渡され、%raxで返されるため、SysV呼び出し規約のように見えます。
ローガン

24

六角形78 70バイト

2"1"\.}/{}A=<\?>(<$\*}[_(A\".{}."&.'\&=/.."!=\2'%<..(@.>._.\=\{}:"<><$

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

この課題は実用的な言語としてはささいすぎではありませんか?;)

辺の長さ6.辺の長さ5の六角形には収まりません。

説明


3
「説明」に本当に一生懸命笑いました。:D
エリックドゥミニル

1
負の数/ゼロの処理が過度に複雑になっている可能性があると思います。私は、そのような2 ^ 64計算を行わないことで、同様のプログラムを辺の長さ5 に収めることができました。ただし、まだまだゴルフが上手ではありません。
FryAmTheEggman

@fryああ、負の数には常に0の先行ゼロがあります... 2 ^ 64が生成されるため、プログラムが短くなります。
user202729

12

Python、31バイト

lambda n:67-len(bin(-n))&~n>>64

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

表現は、&2つの部分のビット単位です。

67-len(bin(-n)) & ~n>>64

67-len(bin(-n))非負の入力のための正しい答えを与えます。ビット長を取得し、67から減算し-0bます。これは、プレフィックスを補正するために64より3多い値です。否定は、否定をn==0使用しても-前に記号が生成されないように調整するための秘is です。

& ~n>>64答えは代わりにすることになり0、負のためにn。ときn<0~n>>64それは得られるとすると、(64ビット整数に)0に等しいので0。の場合n>=0、はに~n>>64評価され-1、実行し&-1ても効果はありません。


Python 2、36バイト

f=lambda n:n>0and~-f(n/2)or(n==0)*64

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

算術的な代替。


9

Javaの8、32 26バイト。

Long::numberOfLeadingZeros

ビルトインFTW。

Kevin Cruijssenのおかげで-6バイト

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


ああ、完全に忘れてしまったnumberOfLeadingZeros.. 28バイトまでゴルフすることができます:n->n.numberOfLeadingZeros(n)
ケビンCruijssen

2
実際にLong::numberOfLeadingZerosは、さらに短い(26バイト)。
ケビンクルーッセン

6
うわー、JavaがPythonに勝つことはあまりありません。おめでとうございます!
エリックドゥミニル

9

C(gcc)、14バイト

__builtin_clzl

TIOで正常に動作します

C(gcc)35 29バイト

f(long n){n=n<0?0:f(n-~n)+1;}

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

6バイトのデニスより

C(gcc)コンパイラフラグ、David Foersterによる29バイト

-Df(n)=n?__builtin_clzl(n):64

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


3
64ビットマシン(またはLP64 / ILP64 / etc ABIを備えた他のマシン)専用であることに注意する価値があります
Ruslan

1
Geez、これは私が思いつくGCCビルトインの__builtin_clzl使用よりもさらに短いです。
デビッドフォースター

@Ruslan:良い点は、long32ビット(Windows x64を含む)のシステムで必要です__builtin_clzll(unsigned long long)。 godbolt.org/z/MACCKf。(インテルの組み込み関数とは異なり、GNU Cの組み込みコマンドは関係なく、1つの機械命令でなんとかという操作のサポートされている32ビットx86では、ブランチやCMOVへclzllコンパイルを行うこと。lzcnt(low half)+32またはlzcnt(high half)か。bsr場合はlzcnt利用できません。
ピーター・コルド

テストケースには "0"が含ま__builtin_clz(l)(l)れますが、ゼロの場合の
MCCCS

1
@MCCCS動作する場合、カウントします。私は最後の答えを保つ理由でもあります
l4m2

6

Perl 6の35の28 26バイト

nwellnhofのおかげで-2バイト

{to .fmt("%064b")~~/^0*/:}

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

数値を受け取り、数値を返す匿名コードブロック。これにより、数値がバイナリ文字列に変換され、先行ゼロがカウントされます。最初の文字が-eg -00000101であるため、負の数に対して機能します。そのため、先行ゼロはありません。

説明:

{                        }  # Anonymous code block
    .fmt("%064b")           # Format as a binary string with 64 digits
                 ~~         # Smartmatch against
                   /^0*/    # A regex counting leading zeroes
 to                     :   # Return the index of the end of the match

6

JavaScript(Node.js)、25バイト

入力をBigIntリテラルとして受け取ります。

f=x=>x<0?0:x?f(x/2n)-1:64

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

0


n=>n<1?0:n.toString(2)-64同じことをしませんか?
イスマエルミゲル

@IsmaelMiguelあなたが意味したと思うn=>n<1?0:n.toString(2).length-64が、それはとにかく動作しません。これだと思います。
アーナルド

1
@IsmaelMiguel心配ありません。:) .toString()アプローチを機能させることは確かに可能ですが、入力としてBigIntリテラルが必要です。それ以外の場合、仮数部は52ビットしかないため、精度が失われると無効な結果になります
アーナルド

1
BigIntサフィックスがあなたのパラメータは非常に...混乱されるのと同じ文字であるという事実
ニール・

1
PPCGの@Neil判読不能コード?? これはできません!修繕!:p
アーナルド


5

J、18バイト

0{[:I.1,~(64$2)#:]

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

J、19バイト

1#.[:*/\0=(64$2)#:]

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

説明:

                #:  - convert 
                  ] - the input to
          (64$2)    - 64 binary digits
         =          - check if each digit equals 
        0           - zero
   [:*/\            - find the running product
1#.                 - sum

1
1#.[:*/\1-_64{.#:(17)は近いが負の数では機能しない:(
Conor O'Brien

@Conor O'Brienナイスなアプローチも!
ガレンイワノフ



4

05AB1E10 9 バイト

·bg65αsd*

I / Oは両方とも整数です

オンラインそれを試してみたり、すべてのテストケースを確認してください

説明:

·         # Double the (implicit) input
          #  i.e. -1 → -2
          #  i.e. 4503599627370496 → 9007199254740992
 b        # Convert it to binary
          #  i.e. -2 → "ÿ0"
          #  i.e. 9007199254740992 → 100000000000000000000000000000000000000000000000000000
  g       # Take its length
          #  i.e. "ÿ0" → 2
          #  i.e. 100000000000000000000000000000000000000000000000000000 → 54
   65α    # Take the absolute different with 65
          #  i.e. 65 and 2 → 63
          #  i.e. 65 and 54 → 11
      s   # Swap to take the (implicit) input again
       d  # Check if it's non-negative (>= 0): 0 if negative; 1 if 0 or positive
          #  i.e. -1 → 0
          #  i.e. 4503599627370496 → 1
        * # Multiply them (and output implicitly)
          #  i.e. 63 and 0 → 0
          #  i.e. 11 and 1 → 11

4

Haskell、56バイト

間違いを見つけてくれてありがとうxnor

f n|n<0=0|1>0=sum.fst.span(>0)$mapM(pure[1,0])[1..64]!!n

かなり多くのメモリを割り当てる可能性があります。オンライン試してください!

もっと小さな定数でテストしたいかもしれません:8ビットを試してみてください!

説明

mapM(pure[0,1])[1..64]mapM(pure[1,0])[1..64]{0,1}641sum.fst.span(>0)


3

Powershell、51バイト

param([long]$n)for(;$n-shl$i++-gt0){}($i,65)[!$n]-1

テストスクリプト:

$f = {

param([long]$n)for(;$n-shl$i++-gt0){}($i,65)[!$n]-1

}

@(
    ,(-1                   ,0 )
    ,(-9223372036854775808 ,0 )
    ,(9223372036854775807  ,1 )
    ,(4611686018427387903  ,2 )
    ,(1224979098644774911  ,3 )
    ,(9007199254740992     ,10)
    ,(4503599627370496     ,11)
    ,(4503599627370495     ,12)
    ,(2147483648           ,32)
    ,(2147483647           ,33)
    ,(2                    ,62)
    ,(1                    ,63)
    ,(0                    ,64)
) | % {
    $n,$expected = $_
    $result = &$f $n
    "$($result-eq$expected): $result"
}

出力:

True: 0
True: 0
True: 1
True: 2
True: 3
True: 10
True: 11
True: 12
True: 32
True: 33
True: 62
True: 63
True: 64

3

Java 8、38バイト

int f(long n){return n<0?0:f(n-~n)+1;}

入力long(64ビット整数)、出力int(32ビット整数)。

@ l4m2のC(gcc)回答のポート。

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

説明:

 int f(long n){       // Recursive method with long parameter and integer return-type
   return n<0?        //  If the input is negative:
           0          //   Return 0
          :           //  Else:
           f(n-~n)    //   Do a recursive call with n+n+1
                  +1  //   And add 1

編集:@lukegのJava 8の回答に表示されているビルトインを使用して、26バイトにすることができます。Long::numberOfLeadingZeros


3

APL + WIN、34バイト

+/×\0=(0>n),(63⍴2)⊤((2*63)××n)+n←⎕

説明:

n←⎕ Prompts for input of number as integer

((2*63)××n) If n is negative add 2 to power 63

(63⍴2)⊤ Convert to 63 bit binary

(0>n), Concatinate 1 to front of binary vector if n negative, 0 if positive

+/×\0= Identify zeros, isolate first contiguous group and sum if first element is zero

3

C#(Visual C#Interactive Compiler)、42バイト

x=>x!=0?64-Convert.ToString(x,2).Length:64

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

C#(Visual C#Interactive Compiler)、31バイト

int c(long x)=>x<0?0:c(x-~x)+1;

さらに短く、@ l4m2のC(gcc)回答に基づいてい ます。 そのような関数を宣言できることを決して知らなかった、@ Danaに感謝!

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


1
これは有効だと思いますか?tio.run/##ZZA/...
ダナ

3

ゼリー 10  9 バイト

-1 Erik the Outgolferのきちんとしたトリックのおかげ(is-non-negativeは単純に

ḤBL65_×AƑ

整数を生成する整数(範囲内)を受け入れる単項リンク。

オンラインでお試しください!または、テストスイートを参照してください。


10は ḤBL65_ɓ>-×

ここに別の10バイトのソリューションがありますが、それは「BOSS」と言われているので好きです...

BoṠS»-~%65

テストスイートはこちら

... BoṠS63r0¤iBoṠS63ŻṚ¤iあるいはBoṠS64ḶṚ¤iも働くだろう。


(デニスから)もう10 byterがあるæ»64ḶṚ¤Äċ0(再びæ»63r0¤Äċ0æ»63ŻṚ¤Äċ0も意志の仕事)



@EriktheOutgolfer「isNonNegativeを掛けるにはもっとゴルファー的な方法があるに違いない」と自分自身に考えて、Ƒすばやい、とてもすてきな仕事を考えていませんでした!
ジョナサンアラン

1
実際、私はかなり長い間理論化してきました。ベクトル化されないことに注意してください!;-)実際には「平坦化してから、すべての要素が非負であるかどうかを確認します」。
エリックアウトゴルファー

2

Perl 5、37バイト

sub{sprintf("%064b",@_)=~/^0*/;$+[0]}

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

または、「文字列化」が許可されていない場合、この46バイト:sub z

sub{my$i=0;$_[0]>>64-$_?last:$i++for 1..64;$i}

s/length$&/$+[0]/(-3バイト);)
ダダ

IMO、subPerl 5関数を含む回答からキーワードを削除することはできません。
nwellnhof

sub他の言語、perl6、powershellなどの回答で削除することに似ているものを見てきました。
KjetilS。18年

Perl6ではsub{}、(匿名?)サブを作成する必要はないと思います。これは、Perl6の回答から省略された理由を説明しています。@nwellnhofには、削除を許可しないことに同意しますsub。(1年前など、まだアクティブだったときがそれがルールでした)
ダダ

今変わりました。そして含まれてい$+[0]ます。
Kjetil S.

2

Swift(64ビットプラットフォーム)、41バイト

というクロージャを宣言します fますInt。このソリューションIntは、64ビットプラットフォームでのみ正しく動作typealiasInt64ます。(32ビットプラットフォームでInt64は、2バイトを追加して、クロージャのパラメータタイプに明示的に使用できます。)

let f:(Int)->Int={$0.leadingZeroBitCount}

Swiftでは、基本的な整数型でさえ標準ライブラリで宣言された通常のオブジェクトです。これはInt、次のようなメソッドとプロパティを持つことができることを意味しますleadingZeroBitCount(標準ライブラリのFixedWidthIntegerプロトコルに準拠するすべてのタイプで必要です)。


面白い。Rustを思い出します。20バイト、.leadingZeroBitCountとしてカウントする必要があると思います
明るい

2

Haskell、24バイト

f n|n<0=0
f n=1+f(2*n+1)

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

これは基本的にKevin CruijssenのJavaソリューションと同じですが、私は独立して見つけました。

引数にはInt、64ビットビルドまたはその他の型が必要Int64です。

説明

引数が負の場合、結果はすぐに0になります。それ以外の場合は、左にシフトして1で埋めます、負の数になるまでます。この充填により、0の特殊なケースを回避できます。

参考のために、ここに明らか/効率的な方法があります:

34バイト

import Data.Bits
countLeadingZeros



1

Perl 5、42 -pバイト

1while$_>0&&2**++$a-1<$_;$_=0|$_>=0&&64-$a

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

ビットストリングベースのソリューションよりも長いが、まともな数学ベースのソリューション。


私が間違えないと本当に機能しない
ダダ

@Dada浮動小数点除算が適切に機能しない場合がいくつかあることがわかります。intこの問題を解決するための電話をかけました。
Xcali

申し訳ありませんが、コピーペーストに失敗したようです。これは私が送信したかったものです;)
ダダ

1

APL(NARS)、15文字、30バイト

{¯1+1⍳⍨⍵⊤⍨64⍴2}

使用方法を確認するには、いくつかの数字をテストします。

  f←{¯1+1⍳⍨⍵⊤⍨64⍴2}
  f ¯9223372036854775808
0
  f 9223372036854775807
1




1

Wolfram言語(Mathematica)、41バイト

正数の式はただ63-Floor@Log2@#&です。置換ルールは、ゼロおよび負の入力の特別な場合に使用されます。

入力は、64ビットの符号付き整数である必要はありません。これにより、入力のフロアが事実上整数に変換されます。64ビット整数の通常の範囲外の数値を入力すると、この整数を格納するのに必要なビット数を示す負の数値が返されます。

63-Floor@Log2[#/.{_?(#<0&):>2^63,0:>.5}]&

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

@ LegionMammal978のソリューションは28バイトでかなり短くなっています。入力は整数でなければなりません。ドキュメントによると、「BitLength[n]事実上、効率的なバージョンですFloor[Log[2,n]]+1。」0ではなく、レポートが正しくない場合を自動的に処理し-∞ます。

Wolfram言語(Mathematica)、28バイト

Boole[#>=0](64-BitLength@#)&

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


1
Boole[#>=0](64-BitLength@#)&28バイトで短くなっています。それはあなたのものと同じ基本概念を使用しますが、適用さBitLengthBooleます。
LegionMammal978

BitLengthを完全に忘れました!
ケリーロウダー

1

bitNumber-math.ceil(math.log(number)/ math.log(2))

例64ビットNUMBER:9223372036854775807 math.ceil(math.log(9223372036854775807)/ math.log(2))ANS:63


あなたはこれに言語名を追加することができれば、人々はおそらく言語名が含まれていませんダウン投票の回答にあるように、それは、素晴らしいことだ
城野2906を
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.