賢明でないビット操作


16

私はでゴルフをするのdcが好きですdcが、ビット単位の操作がないために時々イライラしています。

チャレンジ

4つの指定されたCビット演算と同等のものを実装する機能の提供&|~および^(ビット単位のAND、OR、NOT、およびXOR)。各関数~は、少なくとも32ビットの符号なし整数である2つのオペランドを取ります(1つだけを取ります)。各関数は、オペランドと同じビット幅の符号なし整数を返します。

制限

でサポートされている操作のみを使用できますdc。これらは:

  • + - * / 算術加算、減算、乗算、除算
  • ~ modulo(または言語がサポートしている場合はdivmod)
  • ^ べき乗
  • | モジュラーべき乗
  • v 平方根
  • > >= == != <= < 標準の等式/不等式演算子
  • >> <<ビットシフト演算子。 dcこれらはありませんが、2の累乗による除算/乗算の観点から自明に実装されているため、これらを許可します。

制御構造はdc、(再帰)マクロと(不)平等演算を使用して不器用に構築されます。言語に組み込まれている制御構造を使用できます。

また、論理演算子を && || !直接使用することはできませんが、論理演算子を使用することもできますdc

あなたはビット単位の演算子を使用してはならない &|~および^または自明それらを実装する任意の機能。

さらに、組み込みの文字列のベース変換演算子または関数を使用しないでください。


また、答えの検証に役立つテストプログラムまたはオンラインコンパイラスニペット(ゴルフスコアには含まれていません)の提供を検討してください。


目的の操作をパラメーターとして受け取る1つの関数を実装できますか?また、ビットシフトの代用として2で整数除算できますか?
xnor

@xnor 4つの演算子のそれぞれを実装する4つのパブリック関数を提供する必要があります。また、4つのパブリック関数すべてによって呼び出される共通/ヘルパープライベートメソッド/関数を使用することもできますが、これらはすべてゴルフスコアに含める必要があります。
デジタル外傷

7
@xnorあなたとあなたはxnor演算子も実装する必要があります;-)
デジタル外傷

4つの匿名関数のリストを作成できますか?
-xnor

@MariaTidalTug 4つの関数のリストを返すことと、1つを選択して適用すること(xnorの推奨)と、選択パラメーターを受け入れて選択を実行する1つの関数(wolfhammerの回答)の有効な違いは何ですか?どちらも、コードサイズをユーザーコードにオフロードするため、4つの名前付き関数を持つという点を同様に弱体化しているようです。ユーザーコードは後者の場合よりもその場合の方がおそらくより複雑なので、前者はそれをさらに弱体化させるとさえ主張します。
Runer112

回答:


4

C、134

Cプリプロセッサは悪用するのがかなり楽しいです。基本的に、このマクロは3つの機能を定義して、ao、とx、のためのandorおよびxorそれぞれ。これらの操作のアルゴリズムの唯一の違いは、結果のビットを設定する基準です。

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

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バイトになります(改行とセミコロンを使用)。テストコードは(NOT、OR、AND、XORが連続し、$ 1、$ 2、$ 3、$ 4という名前で見つかる):

> $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 Compiler 0.10.2

nimを学ぶ理由を探していたので、ここに行きます。

コードゴルフでは、変数パラメーターと暗黙的なリターンを活用しました。ドキュメントごとの変数パラメータースタック効率が低くなります。個人的には、暗黙の戻り値は読みにくく、おそらく些細な手順でしか使用しないと思います。

アルゴリズムに関しては、十分に単純です。NOTを除くすべての演算について、各ビットを比較し、予想される真理値表と手動で比較します。出力変数の途中で必要に応じて各ビットを設定します。Nimでは、結果は暗黙的な戻り値です。

notZeroプロシージャが代わりに配置されるように、2つのブール条件をアサートするために組み込みの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)

まだ良い方法を探しています...

これは、スクイーズされていないバージョンに加えて、独自のマシンで実行するためのフルテストハーネスです。
いくつかの入力を実行したい場合は、テストケース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およびorまたはnotおよびxor関数の実行を100回テストし、結果を組み込み演算子によって生成された結果と比較します。eval演算子を無償で使用しているため、非常に遅く、オンラインインタープリターで最大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

JavaScript 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
4つのパブリック関数を提供する必要があります-AND、ORにそれぞれ1つ。NOTおよびXOR。(4つすべてのパブリック関数によって呼び出される共通/ヘルパープライベートメソッド/関数がある場合もあります)。また、NOTが欠落している-おそらくこれらすべての中で最も簡単です
デジタル外傷

@AlexAに感謝します。バイトを追加して、さらにゴルフをしました。
ウルフハンマー

あなたは後にスペースを失うことができるforと置き換えるfunction B(n,m,t)B=(n,m,t)=>。他の機能についても同様です。
アレックスA.

①あなたが使用することができ4*(1<<30)4294967296のためにと-1>>>04294967295のために②でvar、ここで本当に必要?③次の(n,m)=>B(n,m,'a')代わりに書くことができます(n,m)=>{return B(n,m,'a')}
kennytm
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.