不明智的位操作


16

我喜欢打高尔夫球dc,但有时由于dc没有按位操作而感到沮丧。

挑战

提供实现C位操作的相当于提高4层命名的功能&|~^(按位AND,OR,NOT和XOR)。每个函数将使用两个操作数(~仅使用一个),这些操作数至少是32位无符号整数。每个函数将返回与操作数相同的位宽的无符号整数。

限制

您只能使用支持的操作dc。这些是:

  • + - * / 算术加法,减法,乘法和除法
  • ~ 模(如果您的语言支持,则为divmod)
  • ^ 求幂
  • | 模幂
  • v 平方根
  • > >= == != <= < 标准平等/不平等经营者
  • >> <<位移位运算符。 dc没有这些功能,但是由于它们是通过除以2的幂进行琐碎实现的,所以我将允许这些。

dc我使用(递归)宏和(不等式)操作笨拙地构建了控制结构。您可以使用您的语言具有的任何内置控制结构。

也可以使用逻辑运算符 && || !,即使这些运算符不能直接在中使用dc

不能使用位运算符 &|~^或平凡实现它们的任何功能。

另外,您不得使用内置的字符串转换基础运算符或函数。


还请考虑提供一个测试程序或在线编译器代码段(不包含在高尔夫球成绩中)以帮助您验证答案。


我们可以实现一个将所需操作作为参数的功能吗?另外,我们可以整数除以2作为位移的替代品吗?
xnor 2015年

@xnor您必须提供实现四个运算符中的每一个的4个公共函数。您可能还具有所有四个公用函数调用的公用/辅助私有方法/函数,但是所有这些都需要包含在高尔夫球成绩中。
Digital Trauma 2015年

7
@xnor您和您仅还必须实现xnor运算符;-)
Digital Trauma

我可以列出四个匿名函数吗?
xnor 2015年

@MariaTidalTug返回四个功能列表与手动选择和应用一个功能(如xnor建议)与使一个功能接受选择参数并自行执行选择(如wolfhammer回答)之间的有效区别是什么?它们似乎都破坏了具有四个命名函数的意义,因为它们将代码大小转移到了用户代码上。我什至认为前者对它的破坏更大,因为在这种情况下用户代码可能比后者更复杂。
Runer112

Answers:


4

C,134

C预处理器很容易被滥用。基本上这个宏定义了3个功能,ao,和x,对andorxor分别。这些操作在算法上的唯一区别是在结果中设置该位的标准。

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 2015年

4

ised 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}}:};

异或:

@4{:$6::{$5::{x_0}:<>$5::{x_1}}:};

这将使我们达到156个字节(带有换行符和分号)。一个测试代码就是(连续,非,或,与,异或,在名称$ 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编译器0.10.2

我一直在寻找学习尼姆的理由,所以我们开始吧。

对于代码高尔夫球,我利用了可变参数和隐式返回。根据文档,可变参数的堆栈效率较低。就我个人而言,我发现隐式返回值更难阅读,并且可能只会在琐碎的过程中使用它们。

至于算法,它们很简单。对于除NOT以外的所有操作,我们将每个位进行比较,然后手动将其与我们的期望真值表进行比较。根据需要在输出变量中设置每个位。在Nim中,结果是隐式返回值。

我不确定是否允许我们使用内置的OR和AND声明两个布尔条件,因此将notZero过程放在了它们的位置。

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 2015年

我无法重现。您的计算器处于16进制模式吗?
cory.todd 2015年

我添加了一个类似于笔名117的测试工具。
cory.todd 2015年

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和(或非)xor函数的运行进行100次测试,并将结果与​​内置运算符产生的结果进行比较。由于免费使用eval运算符,它的运行速度很慢,并且在线解释器可能要花费大约一分钟的时间。但是,如果一切顺利,执行应该以无输出结束,因为会发现发现的任何差异。

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
您需要提供四个公共函数-每个用于AND或OR。不和。(您可能还具有由所有四个公共函数调用的公共/辅助私有方法/函数)。此外,你缺少的不是-也许是最简单所有这些做
数字创伤

谢谢@AlexA。我添加了字节并打了一些球。
wolfhammer

之后,您可能会失去空格for并替换function B(n,m,t)B=(n,m,t)=>。其他功能也是如此。
Alex A.

①您可以使用4*(1<<30)4294967296和-1>>>04294967295。②是否var真的需要?③您可以写(n,m)=>B(n,m,'a')而不是(n,m)=>{return B(n,m,'a')}
kennytm
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.