数字はどのくらい偶数ですか?


47

古代ギリシア人は、これらのことを一重および二重の偶数と呼んでいました。単一の偶数の例は14です。1を2で割ると、その時点で奇数(7)になり、その後2で割り切れなくなります。二重の偶数は20です。2で2で割ると、5になります。

あなたの仕事は、整数を入力として受け取り、整数として2で割り切れる回数を可能な限り少ないバイト数で出力する関数またはプログラムを作成することです。入力はゼロ以外の整数(言語の制限内で正または負の値)になります。

テストケース:

14 -> 1

20 -> 2

94208 -> 12

7 -> 0

-4 -> 2

最小バイトの答えが勝ちです。

ヒント:数値を2を基数に変換してみてください。


11
@AlexL。また、それが奇数になることはないので、無限に均等に見ることもできます。スタックオーバーフローが許可されている場合、数バイトを節約できます;)
Geobits

1
The input will be a nonzero integerゼロが潜在的な入力であるというコメントに続いて、これを編集する必要がありますか?
-trichoplax

2
これは、2進評価または2進注文と呼ばれます。
ポール

7
ところで、ウィキペディアによると、0のp進評価は無限と定義されています。
ポール

3
なんて奇妙な質問でしょう!
corsiKa

回答:


23

ゼリー、4 バイト

Æfċ2

Jellyの最新バージョンではÆEḢ(3バイト)動作します。

Æf      Calculate the prime factorization. On negative input, -1 appended to the end.
  ċ2    Count the 2s.

ここで試してみてください


これは負の入力でも機能します。
リトシアスト

1
@ThomasKwaそれは重要ではないと思います。たぶんメタ質問?
orlp

ÆEḢは大丈夫ですか?奇数の場合、実際には0を出力します。
-busukxuan

@busukxuan±1では機能しません。
-lirtosiast

1
@Tyzoid Jellyは、デフォルトではオフラインインタープリターで独自のコードページを使用します。1 ページの文字は1バイトです。
リトシスト

93

x86_64マシンコード、4バイト

BSF(ビットスキャンフォワード)命令はまさにこれを行います!

0x0f    0xbc    0xc7    0xc3

gccスタイルのアセンブリでは、これは次のとおりです。

    .globl  f
f:
    bsfl    %edi, %eax
    ret

入力はEDIレジスタで指定され、標準の64ビット呼び出し規約に従ってEAXレジスタで返されます。

2の補数のバイナリエンコーディングのため、これは-veおよび+ veの数値に対して機能します。

また、「ソースオペランドの内容が0の場合、デスティネーションオペランドの内容は未定義です」というドキュメントにも関わらずです。、Ubuntu VMでは、出力f(0)が0 であることがわかりました。

手順:

  • 上に保存evenness.sしてと組み立てgcc -c evenness.s -o evenness.o
  • 次のテストドライバーをとして保存し、次を使用evenness-main.cしてコンパイルしgcc -c evenness-main.c -o evenness-main.oます。
#include <stdio.h>

extern int f(int n);

int main (int argc, char **argv) {
    int i;

    int testcases[] = { 14, 20, 94208, 7, 0, -4 };

    for (i = 0; i < sizeof(testcases) / sizeof(testcases[0]); i++) {
        printf("%d, %d\n", testcases[i], f(testcases[i]));
    }

    return 0;
}

次に:

  • リンク: gcc evenness-main.o evenness.o -o evenness
  • 実行: ./evenness

@FarazMasroorは、この回答がどのように導き出されたのかについての詳細を求めました。

私はx86アセンブリの複雑さよりも精通しているため、通常はコンパイラを使用してアセンブリコードを生成します。私は経験からなどのgcc拡張機能__builtin_ffs()__builtin_ctz()__builtin_popcount()を知っおり通常はx86で1つまたは2つの命令にコンパイルおよびアセンブルします。だから私は次のような関数から始めました:

int f(int n) {
    return __builtin_ctz(n);
}

オブジェクトコードに至るまで通常のgccコンパイルを使用する代わりに、-Sオプションを使用して、アセンブリのみにコンパイルすることができますgcc -S -c evenness.c。これにより、次のevenness.sようなアセンブリファイルが作成されます。

    .file   "evenness.c"
    .text
    .globl  f
    .type   f, @function
f:
.LFB0:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    movl    %edi, -4(%rbp)
    movl    -4(%rbp), %eax
    rep bsfl    %eax, %eax
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE0:
    .size   f, .-f
    .ident  "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.1) 4.8.4"
    .section    .note.GNU-stack,"",@progbits

これの多くはゴルフアウトすることができます。特に、シグネチャを持つ関数の 呼び出し規約int f(int n);が素晴らしくシンプルであることを知ってい入力パラメータがEDIレジスタに渡され、戻り値がEAXレジスタに返されます。そのため、ほとんどの命令を取り出すことができます。それらの多くは、レジスタの保存と新しいスタックフレームのセットアップに関係しています。ここではスタックを使用せず、EAXレジスタのみを使用するため、他のレジスタを心配する必要はありません。これにより、「ゴルフ」アセンブリコードが残ります。

    .globl  f
f:
    bsfl    %edi, %eax
    ret

@zwolが指摘しているように、最適化されたコンパイルを使用して同様の結果を達成することもできます。特に-Os、上記の命令を正確に生成します(追加のオブジェクトコードを生成しないアセンブラディレクティブをいくつか追加します)。

これはでアセンブルgcc -c evenness.s -o evenness.oされ、上記のようにテストドライバープログラムにリンクできます。

このアセンブリに対応するマシンコードを決定するには、いくつかの方法があります。私のお気に入りは、gdb disassdisassemblyコマンドを使用することです。

$ gdb ./evenness
GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1
...
Reading symbols from ./evenness...(no debugging symbols found)...done.
(gdb) disass /r f
Dump of assembler code for function f:
   0x00000000004005ae <+0>: 0f bc c7    bsf    %edi,%eax
   0x00000000004005b1 <+3>: c3  retq   
   0x00000000004005b2 <+4>: 66 2e 0f 1f 84 00 00 00 00 00   nopw   %cs:0x0(%rax,%rax,1)
   0x00000000004005bc <+14>:    0f 1f 40 00 nopl   0x0(%rax)
End of assembler dump.
(gdb) 

そのため、bsf命令のマシンコードはis 0f bc c7とforでretあることがわかりc3ます。


これを2として数えませんか?
リルトシアスト

2
機械語/バイトダンプコードを学習するにはどうすればよいですか?オンラインで何かを見つけることができません
ファラズマスロ

1
これは、Cの呼び出し規約を満たしていません。x86-32では、引数はスタックで渡されます。x86-64では、引数は%rdiで渡されます。コンパイラがたまたま%eaxに引数の古いコピーを残しているため、テストハーネス内でのみ動作するようです。evenness-main.c異なる最適化設定でハーネスをコンパイルすると、破損します。私にとってそれはで壊れる-O-O2または-O3
アンデルスカセオルグ

1
@AndersKaseorg-それを指摘してくれてありがとう。現在はx86_64に制限しているため、入力はRDIで行われます。
デジタル外傷

3
「また、[...]と書かれているドキュメントにもかかわらず」-あなたが得る値は、必然的にドキュメントに同意する それはあなたとは異なる価値を与える他のプロセッサーモデルを除外しません。
hvd

25

Python、25バイト

lambda n:len(bin(n&-n))-3

n & -n 最下位ビット以外のすべてをゼロにします。例:

100010101010100000101010000
            v
000000000000000000000010000

末尾のゼロの数に興味があるので、を使用してバイナリ文字列に変換しbinます"0b10000"。これは、上記の数に対してになります。について0bも、についても気にしないので1、その文字列の長さから3を引きます。


私の答えを投稿した後、私はあなたのものが非常に賢いと思ったので、私はそれをPythに変換し、あなたのものが私のものよりも短いかどうかを確認しようとしました。len(bin(_))の代わりにlog2を使用してl。&Q_Qを生成しました。それは私のPythの回答と同じ長さで、別のPythの回答でもありました。Pythでは6バイトより短くならないようです
...-busukxuan



13

JavaScriptのES6、22の 19バイト

f=x=>x%2?0:f(x/2)+1

再帰が最短ルートのようです。


おお あなたは私を倒した!うまく行って:) 1
コナーベル

6

Pyth、8バイト

lec.BQ\1
     Q    autoinitialized to eval(input())
   .B     convert to binary string
  c   \1  split on "1", returning an array of runs of 0s
 e        get the last run of 0s, or empty string if number ends with 1
l         take the length

たとえば、のバイナリ表現94208は次のとおりです。

10111000000000000

1sで分割し、結果の配列の最後の要素を取得すると、次のようになります。

000000000000

これは12個のゼロであるため、「12-ly even」です。

これは、x / 2本質的にx >> 1-つまり、のビットシフト権であるため機能し1ます。したがって、数値は、LSBが2で割り切れる場合にのみ0(最後の桁が10進数が10で割り切れる場合と同様0)。




6

MATL、5バイト

Yf2=s

これはすべての整数で機能します。

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

Yf      % implicit input. Compute (repeated) prime factors. For negative input
        % it computes the prime factors of the absolute value, except that for
        % -1 it produces an empty array instead of a single 1
2=s     % count occurrences of "2" in the array of prime factors

「そして今、まったく違う何かのために...」
ビーカー

6

C、36(28)バイト

int f(int n){return n&1?0:f(n/2)+1;}

(非ゼロ引数が指定されたため、ゼロ引数をテストしていません。)

更新(コメントへの応答):K&Rスタイルの関数宣言を許可する場合、28バイトバージョンを使用できます。

f(n){return n&1?0:f(n/2)+1;}

この場合、コンパイラがデフォルトの両方nと戻りタイプfto を使用することに依存していintます。ただし、このフォームはC99で警告を生成し、有効なC ++コードとしてコンパイルしません。


変更する場合int n-> nそれはまだ有効なCコードであり、4文字を切り捨てます。
ジョシュ

いい視点ね。私はそれが少なくともC99で警告をトリガーすると言うつもりでしたが、戻り値の型も省略します。そして、どちらもC ++でエラーを引き起こします。ですから、答えを適切に変えています。
ヴィクトルトス

5

Java 7、39、または44バイト

int s(int a){return a%2!=0?0:s(a/2)+1;}

int s(int a){return a%2!=0|a==0?0:s(a/2)+1;}

イェイ再帰!私は使用しなければなりませんでした!=負の入力でオーバーフローしないように短い比較の代わり必要がありましたが、それ以外は非常に簡単です。奇数の場合、ゼロを送信します。偶数の場合は、追加して再度実行します。

現在ゼロの出力が不明であるため、2つのバージョンがあります。最初はスタックがオーバーフローするまで再帰し、0は無限に偶数であるため、何も出力しません。2つ目は、出力用に素敵で安全な、おそらく数学的に厳密でない0を吐き出します。


4

JavaScript(ES6)、20バイト 19バイト。

f=x=>~x%2&&1+f(x/2)

@nimiによるJavaScriptへのHaskellソリューションの移植版です。「短絡」プロパティを使用し、&&falsey(この場合は-0)の場合は左側を返し、そうでない場合は右側を返します。実装するためにodd x = 0、我々はそのため左側作る1 - (x % 2)0経由し&&、そうでなければ、私たちはに再帰しました1 + f(x / 2)

1 - (x % 2)as のシェービングは、(~x) % 2以下の@Neilによるものであり、上記の関数が-0小さな奇数に対して発光する奇妙なプロパティを持っています。この値は、整数がIEEE754 doubleであるというJSの決定の特性です。このシステムは、別個を有し+0且つ-0その特殊ケースに入れJavaScriptでれるべき===互いに。~オペレータは、小さな奇数陰性偶数であろう数、32ビット符号付き整数のビット単位の反転を計算します。(正の数Math.pow(2, 31) + 1例が生成する0のではなく-0)32ビット符号付き整数に奇妙な制限は、任意の他の効果を有していません。特に、正確性には影響しません。


~x&1は、より短いバイトです1-x%2
ニール

@Neilとてもクール。それはやや直感に反する特性を持っていますが、とにかくそれを取ります。
CR

4

Perl 6の、23の 18バイト

{+($_,*/2...^*%2)}

使用法

> my &f = {+($_,*/2...^*%2)}
-> ;; $_? is raw { #`(Block|117104200) ... }
> f(14)
1
> f(20)
2
> f(94208)
12
> f(7)
0
> f(-4)
2

4

ルビー24バイト

私の最初のコードゴルフの提出(はい!)

("%b"%$*[0])[/0*$/].size

どうやってここに来たの

最初に、問題を回避するために実際に仕様を満たすコードを取得したかったので、バイト数に関係なくメソッドを構築しました。

def how_even(x, times=1)
  half = x / 2
  if half.even?
    how_even(half, times+1)
  else
    times
  end
end

この知識で、関数をwhileループに再帰$*し、入力として(ARGV)を追加し、iが奇数になるまでに半分になった回数のカウントとして追加しました。

x=$*[0];i=1;while(x=x/2)%2<1;i+=1;end;i

私はこれを非常に誇りに思っており、2で割ったことはすべて私にとって少しバイナリに聞こえた、私はソフトウェアエンジニアでありながらコンピューター科学者ではないことを思いついたが、これは頭に浮かんだ最初のものではなかった。

そこで、入力値がバイナリでどのように見えるかについていくつかの結果を収集しました。

input      in binary      result
---------------------------------
   14               1110   1
   20              10100   2
94208  10111000000000000  12

結果は、数値が奇数になる前に横断しなければならない左の位置の数であることに気付きました。

いくつかの単純な文字列操作を行って、最後に出現した1で文字列を分割し、残りの0の長さをカウントしました。

("%b"%$*[0])[/0*$/].size

("%b" % x)フォーマットを使用して数値をバイナリに変換し、String#sliceを使用して文字列をスライスします。

私はこのクエストでルビーについていくつかのことを学びましたが、すぐにもっとゴルフを楽しみにしています!


2
プログラミングパズルとCode Golf Stack Exchangeへようこそ。これは素晴らしい答えです。私は説明が本当に好きです。+1!より多くのコードゴルフのチャレンジが必要な場合は、コードゴルフタグをクリックしてください。あなたの答えをもっと見るのを楽しみにしています。
wizzwizz4

1
ご不明な点がございましたら、お気軽にお問い合わせください。@wizzwizz4コメントの冒頭に入力して返信してください。(これはすべてのユーザー名で機能します!)
wizzwizz4


4

C、37バイト

f(int x){return x?x&1?0:1+f(x/2):0;} 最後のビットが0になるまで再帰的にチェックします。


また、f(int n){return __builtin_ctz(n);}gcc拡張機能を使用する場合もあります。またはさらに#define f __builtin_ctz
デジタル外傷

を削除しint ます。戻り値の型と同様に、暗黙的です。
luser droog

@luserdroog、つまりf(n){...}?GCCはそれをコンパイルしません。私はCの専門家ではありませんが、クイック検索で、この機能がCのより新しいバージョンで削除された可能性があることがわかりました。
アンディソファー

@AndySofferなるほど。たぶん-ansi-gnu99?私はそれが機能するようになったことを知っています。私はそれについてのヒントの答えを書きました!
luser droog

3

Haskell、28バイト

f x|odd x=0|1<2=1+f(div x 2)

使用例:f 94208-> 12

数が奇数の場合、結果は0になります。それ以外の場合は、1半分の数の再帰呼び出しが追加されます。


div x 2?どうしてx/2
CalculatorFeline

@CatsAreFluffy:Haskellには非常に厳密な型システムがあります。div整数除算、/浮動小数点除算です。
-nimi

3

Befunge、20

&:2%#|_\1+\2/#
   @.<

コードの実行は右に移動し(おかげ末尾に最初の行の2番目の文字にラップアラウンドし続ける#まで)2%を出力1させ、_その後、左に方向を切り替えること|にラップアラウンドまで、<第2行に出力して終了します。ループを通過するたびにスタックの2番目から2番目の要素をインクリメントし、次に2で除算します。


3

網膜29 17

+`\b(1+)\1$
;$1
;

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

Martinのおかげで2バイト節約されました!

単項入力を取ります。これは1sの最大数と繰り返し一致し、その1sの数が残りのsと正確に一致し1ます。これを行うたび;に、文字列の先頭にa が追加されます。最後;に、文字列のs の数をカウントします。

10進数の入力が必要な場合は、次を追加します。

\d+
$0$*1

プログラムの開始まで。




3

6502機械語、7バイト

アキュムレータ内の非ゼロ値の最下位1ビットの場所の値を検索し、結果をレジスタXに残します。

A2 FF E8 4A 90 FC 60

これをe-tradition.net6502シミュレーターで実行するには、接頭辞のA9後に8ビット整数を付けます。

これは次のように分解されます。

count_trailing_zeroes:
    ldx #$FF
loop:
    inx
    lsr a     ; set carry to 0 iff A divisible by 2, then divide by 2 rounding down
    bcc loop  ; keep looping if A was divisible by 2
    rts       ; return with result in X

これは、Cがint少なくとも16ビットである必要があることを除いて、次のCと同等です。

unsigned int count_trailing_zeroes(int signed_a) {
    unsigned int carry;
    unsigned int a = signed_a;  // cast to unsigned makes shift well-defined
    unsigned int x = UINT_MAX;
    do {
        x += 1;
        carry = a & 1;
        a >>= 1;
    } while (carry == 0);
    return x;
}

MX = 01(16ビットアキュムレータ、8ビットインデックス)を想定した65816でも同じことができ、上記のCスニペットと同等です。


2

Brachylog27 15バイト

$pA:2xlL,Al-L=.

説明

$pA             § Unify A with the list of prime factors of the input
   :2x          § Remove all occurences of 2 in A
      lL,       § L is the length of A minus all the 2s
         Al-L=. § Unify the output with the length of A minus L

2

CJam、8バイト

rizmf2e=

整数、絶対値、素因数分解、2をカウントします。


2

JavaScript ES6、36 38バイト

@ETHproductionsのおかげで2バイトのゴルフ

かなり退屈な答えですが、それは仕事をします。実際に別の答えとあまりにも似ているかもしれません。提案された変更を追加したら、私は私のものを削除します。

b=>{for(c=0;b%2-1;c++)b/=2;alert(c)}

実行するには、変数をa=>{for...匿名関数として変数()に割り当て、で呼び出しますa(100)


素敵な答え!b%2==0変更することができb%2-1、かつc++の最後の部分の内側に移動することができfor声明。これも機能すると思います:b=>eval("for(c=0;b%2-1;b/=2)++c")
ETHproductions

@ETHproductionsだからできる!ナイスキャッチ:)
コナーベル

もう1バイト:b%2-1=> ~b&1また、これはの入力で失敗すると思います。これは0b&&~b&1
ETHproductions

これを負の数でテストしてコンピューターを凍結しました。b%2-1負の奇数のチェックは失敗します。
パトリックロバーツ


2

DUP、20バイト

[$2/%0=[2/f;!1+.][0]?]f:

Try it here!

再帰に変換され、出力がスタックのトップ番号になりました。使用法:

94208[2/\0=[f;!1+][0]?]f:f;!

説明

[                ]f: {save lambda to f}
 2/\0=               {top of stack /2, check if remainder is 0}
      [     ][ ]?    {conditional}
       f;!1+         {if so, then do f(top of stack)+1}
              0      {otherwise, push 0}

2

Japt、9 5バイト

¢w b1

オンラインでテストしてください!

前のバージョンは5バイトでなければなりませんでしたが、これは実際に機能します。

使い方

       // Implicit: U = input integer
¢      // Take the binary representation of U.
w      // Reverse.
b1     // Find the first index of a "1" in this string.
       // Implicit output

2

C、44 40 38 36バイト

@JohnWHSmithに感謝します@luserdroogに感謝します

a;f(n){for(;~n&1;n/=2)a++;return a;}

ideoneでライブテストを行います。


高価なもの!(n%2)を素敵な小さなものに置き換えることで、1バイトを節約でき~n&1ます。
ジョンWHスミス

@johnWHSmith。あれはよかった!!ありがとう
削除

を削除し=0ます。グローバルは暗黙的に0に初期化されます。
luserをドローグ

@luserdroog。おかげで、私はそれについて知りませんでした。
削除

私が間違っている場合は修正しますが、この関数はグローバル変数を使用aするため、最初に呼び出されたときにのみ動作することが保証されていませんか?私はそれが許可されたことを知りませんでした。
パトリックロバーツ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.