การดำเนินการบิตที่ไม่ฉลาด


16

ฉันชอบเล่นกอล์ฟdcแต่บางครั้งฉันก็รู้สึกท้อแท้เพราะdcไม่มีปฏิบัติการในระดับบิต

ท้าทาย

ให้สี่ฟังก์ชั่นการตั้งชื่อที่ใช้เทียบเท่าของการดำเนินงานคบิต&, |, ~และ^(บิต AND, OR, NOT และแฮคเกอร์) แต่ละฟังก์ชันจะใช้ตัวถูกดำเนินการสองตัว ( ~รับเพียงตัวเดียว) ซึ่งเป็นจำนวนเต็มอย่างน้อย 32 บิตที่ไม่ได้ลงชื่อ แต่ละฟังก์ชั่นจะคืนค่าจำนวนเต็มที่ไม่ได้ลงนามซึ่งมีความกว้างบิตเท่ากับตัวถูกดำเนินการ

การ จำกัด

คุณสามารถใช้การดำเนินการที่ได้รับการสนับสนุนdcเท่านั้น เหล่านี้คือ:

  • + - * / การบวกการลบการคูณและการหารทางคณิตศาสตร์
  • ~ modulo (หรือ divmod หากภาษาของคุณรองรับ)
  • ^ การยกกำลัง
  • | การยกกำลังแบบแยกส่วน
  • v รากที่สอง
  • > >= == != <= < ผู้ประกอบการความเสมอภาค / ความไม่เท่าเทียมกันมาตรฐาน
  • >> <<ผู้ประกอบการเปลี่ยนบิต dcไม่มีสิ่งเหล่านี้ แต่เนื่องจากมีการใช้งานเพียงเล็กน้อยในแง่ของการหาร / การคูณด้วยพลังของ 2 ดังนั้นฉันจะอนุญาตสิ่งเหล่านี้

โครงสร้างการควบคุมในการdcสร้างของฉันอย่างงุ่มง่ามโดยใช้มาโคร (แบบเรียกซ้ำ) และการดำเนินการที่เท่าเทียมกัน คุณสามารถใช้โครงสร้างการควบคุมที่มีอยู่ในภาษาของคุณ

คุณยังอาจจะใช้ดำเนินการทางตรรกะ แม้ว่าเหล่านี้ไม่ได้โดยตรงที่มีอยู่ใน&& || !dc

คุณต้องไม่ใช้ผู้ประกอบการระดับบิต & , |, ~และ^หรือฟังก์ชั่นใด ๆ ที่นิด ๆ ใช้พวกเขา

นอกจากนี้คุณต้องไม่ใช้ตัวดำเนินการหรือฟังก์ชันการแปลงเบสสตริงในตัว


โปรดลองเสนอโปรแกรมทดสอบหรือตัวอย่างข้อมูลคอมไพเลอร์ออนไลน์ (ไม่รวมอยู่ในคะแนนกอล์ฟ) เพื่อช่วยยืนยันคำตอบของคุณ


เราสามารถใช้ฟังก์ชั่นเดียวที่ใช้การดำเนินการที่ต้องการเป็นพารามิเตอร์ได้หรือไม่? นอกจากนี้เราสามารถหารด้วย 2 เป็นจำนวนเต็มสำหรับการเปลี่ยนบิตได้หรือไม่?
xnor

@xnor คุณต้องมีฟังก์ชั่นสาธารณะ 4 ตัวที่ใช้แต่ละตัวดำเนินการทั้งสี่ คุณอาจมีวิธีการ / ฟังก์ชั่นส่วนตัว / ผู้ช่วยส่วนตัวที่เรียกโดยฟังก์ชั่นสาธารณะทั้งสี่ แต่สิ่งเหล่านี้จะต้องรวมอยู่ในคะแนนกอล์ฟ
บาดเจ็บทางระบบดิจิตอล

7
@xnor คุณและคุณจะต้องใช้ตัวดำเนินการ xnor ;-) ด้วย
Digital Trauma

ฉันสามารถสร้างรายการฟังก์ชันที่ไม่ระบุชื่อสี่รายการได้หรือไม่
xnor

@MariaTidalTug ความแตกต่างที่มีประสิทธิภาพระหว่างการส่งคืนรายการฟังก์ชันสี่รายการและการเลือกและการใช้ด้วยตนเอง (ตามที่ xnor แนะนำ) ด้วยตนเองเมื่อเทียบกับการมีฟังก์ชันหนึ่งที่ยอมรับพารามิเตอร์การเลือกและดำเนินการเลือกเอง (ดังที่ wolfhammer ตอบ) พวกเขาทั้งคู่ดูเหมือนจะบ่อนทำลายจุดที่มีฟังก์ชั่นที่ตั้งชื่อไว้สี่ตัวในขณะที่พวกเขาลดขนาดโค้ดลงบนรหัสผู้ใช้ ฉันยังยืนยันว่าอดีตนั้นทำลายมันมากกว่าเนื่องจากรหัสผู้ใช้อาจซับซ้อนกว่าในกรณีนั้นมากกว่าในกรณีหลัง
Runer112

คำตอบ:


4

C, 134

ตัวประมวลผลล่วงหน้า C ค่อนข้างสนุกกับการละเมิด โดยทั่วไปแมโครนี้กำหนด 3 ฟังก์ชั่นa, oและxสำหรับand, orและxorตามลำดับ ความแตกต่างเพียงอย่างเดียวในอัลกอริทึมสำหรับการดำเนินการเหล่านี้คือเกณฑ์สำหรับการตั้งค่าบิตในผลลัพธ์

notnเป็นฟังก์ชั่น

#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
อุ่ย ลืมเรื่องนั้นไป คงที่ในขณะนี้
นามแฝง

4

มีค่า 76 ไบต์

ised ยังไม่มีการดำเนินการระดับบิต - มักจะน่ารำคาญ แต่ตอนนี้ยินดีต้อนรับเพราะเราจำเป็นต้องใช้พวกเขาจริงๆ

ฟังก์ชั่นจะถูกเก็บไว้ในช่องหน่วยความจำที่กำหนดหมายเลขไว้ (ไม่มีชื่อ verbose)

การแปลงไปยังและจากไบนารี:

@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 ไบต์ (ด้วยการขึ้นบรรทัดใหม่และอัฒภาค) รหัสทดสอบจะเป็นแบบต่อเนื่อง (ไม่ใช่, OR, และ, XOR, อยู่ภายใต้ชื่อ $ 1, $ 2, $ 3, $ 4):

> $1::{6}
4294967289
> $2::{12 11}
15
> $3::{12 11}
8
> $4::{12 11}
7

แต่แน่นอนหรือไม่ใช่ทั้งหมดที่เราต้องการจริงๆและสิ่งต่าง ๆ สามารถทำให้ง่ายขึ้น:

@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)

คอมไพเลอร์นิ่ม 0.10.2

ฉันกำลังมองหาเหตุผลที่จะเรียนรู้สิ่งต่าง ๆ ดังนั้นที่นี่เราไป

สำหรับ code golf ฉันมีพารามิเตอร์ที่ใช้ประโยชน์และผลตอบแทนโดยปริยาย พารามิเตอร์ตัวแปรตามเอกสารประกอบมีประสิทธิภาพน้อยกว่าสแต็ก โดยส่วนตัวแล้วฉันพบว่าการกลับมาโดยปริยายนั้นยากต่อการอ่านมากขึ้นและอาจใช้พวกมันในขั้นตอนเล็กน้อยเท่านั้น

สำหรับอัลกอริทึมนั้นง่ายพอ สำหรับการดำเนินการทั้งหมดยกเว้นไม่เราเปรียบเทียบแต่ละบิตและทำการเปรียบเทียบด้วยตนเองกับตารางความจริงที่เราคาดไว้ ตั้งค่าแต่ละบิตตามต้องการไปพร้อมกันในตัวแปรเอาต์พุตของเรา ใน Nim ผลลัพธ์คือค่าส่งคืนโดยนัย

ฉันไม่แน่ใจว่าเราได้รับอนุญาตให้ใช้ built-in 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

ฉันทำซ้ำไม่ได้ เครื่องคิดเลขของคุณอยู่ในโหมดฐาน 16 หรือไม่?
cory.todd

ฉันเพิ่มสายรัดทดสอบที่คล้ายกับของเทียม 116
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.";

ชุดทดสอบ

รหัสนี้ทดสอบการทำงานของฟังก์ชั่นของฉันและ, หรือไม่, และ xor แต่ละครั้ง 100 ครั้งกับอินพุตที่ไม่ได้ลงนาม 64- บิตที่สม่ำเสมอและเปรียบเทียบผลลัพธ์กับผลลัพธ์ที่สร้างโดยโอเปอเรเตอร์ในตัว เนื่องจากการใช้งานตัวดำเนินการประเมินผลฟรีมันค่อนข้างช้าและอาจใช้เวลาประมาณหนึ่งนาทีกับล่ามออนไลน์ แต่ถ้าทุกอย่างเป็นไปด้วยดีการประมวลผลควรจบลงโดยไม่มีเอาต์พุตเนื่องจากความคลาดเคลื่อนที่พบจะถูกพิมพ์

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 ไม่ใช่และแฮคเกอร์ (คุณอาจมีวิธีการ / ฟังก์ชั่นส่วนตัว / ผู้ช่วยส่วนตัวที่เรียกโดยฟังก์ชั่นสาธารณะทั้งสี่) นอกจากนี้คุณยังขาดสิ่งที่ต้องทำ - สิ่งที่ง่ายที่สุดที่ควรทำ
Digital Trauma

ขอบคุณ @AlexA ฉันได้เพิ่มไบต์และ golfed มันเพิ่มเติม
wolfhammer

คุณจะสูญเสียพื้นที่หลังforและแทนที่ด้วยfunction B(n,m,t) B=(n,m,t)=>เช่นเดียวกันสำหรับฟังก์ชั่นอื่น ๆ
Alex A.

①คุณสามารถใช้4*(1<<30)สำหรับ 4294967296 และ-1>>>0สำหรับ 4294967295 varnecessary จำเป็นจริง ๆ ไหมที่นี่ ③คุณสามารถเขียน(n,m)=>B(n,m,'a')แทน(n,m)=>{return B(n,m,'a')}
kennytm
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.