วิธีกำหนด“ หรือ” ตามหลักเหตุผล


36

เมื่อเร็ว ๆ นี้ฉันเจอปัญหาที่ทำให้ฉันต้องกำหนดตัวดำเนินการเชิงตรรกะ "หรือ" โดยทางโปรแกรม แต่ไม่ได้ใช้ตัวดำเนินการเอง

สิ่งที่ฉันคิดไว้คือ:

OR(arg1, arg2)
  if arg1 = True and arg2 = True
     return True

  else if arg1 = True and arg2 = False
     return True

  else if arg1 = False and arg2 = True
     return True

  else:
     return False

ตรรกะนี้ถูกต้องหรือฉันพลาดอะไรไป?


10
@gnat: เพื่อความยุติธรรมตารางความจริงจะแสดงรายการผลลัพธ์สำหรับแต่ละชุดของอินพุตและบทความ Wikipedia ให้คำอธิบายเกี่ยวกับฟังก์ชัน ฉันคิดว่าสิ่งที่ OP ถามจริงๆคือวิธีกำหนดตรรกะหรือการเขียนโปรแกรมโดยไม่ต้องใช้ตัวดำเนินการเอง
Blrfl

6
@ user3687688 คุณช่วยอธิบายสิ่งที่เราอนุญาตให้ใช้ได้หรือไม่?
fredoverflow

4
คำถามนี้ได้เริ่มต้นกล้ามเนื้อกระตุกรวมของไมโครเพิ่มประสิทธิภาพ;)
ร็อบ

8
คุณสามารถใช้ผู้ประกอบการที่สามreturn arg1 ? arg1 : arg2;
Matthew

4
ฉันต้องรู้ว่าทำไมคุณต้องกำหนดorโอเปอเรเตอร์อีกครั้ง
Kyle Strand

คำตอบ:


102

ฉันจะบอกว่าถูกต้อง แต่คุณไม่ย่อหย่อนมันลงไปในบางสิ่งเช่นนี้หรือไม่?

or(arg1, arg2)
    if arg1 == true
        return true
    if arg2 == true
        return true

    return false

เนื่องจากคุณกำลังทำการเปรียบเทียบหรือไม่ฉันไม่คิดว่าคุณจะต้องตรวจสอบชุดค่าผสม มันเป็นเรื่องสำคัญหากหนึ่งในนั้นเป็นความจริงที่จะกลับมาจริง มิฉะนั้นเราต้องการคืนค่าเท็จ

หากคุณกำลังมองหาเวอร์ชั่นที่สั้นกว่าซึ่งมีรายละเอียดน้อยกว่าสิ่งนี้จะใช้งานได้:

or(arg1, arg2)
    if arg1
        return arg1
    return arg2

6
คุณสามารถลบ "else" ในบรรทัดที่ 4 (เหลือไว้เพียงif arg2 == true)
Dawson Toth

1
@DawsonToth มีหลายวิธีที่คุณสามารถหมุนได้ขึ้นอยู่กับว่าคุณต้องการที่จะ verbose หรือข้นจริงๆ ฉันจะมีความสุขกับสิ่งอื่นถ้า แต่ดูเหมือนว่านี่เป็นคำถามรหัสหลอกดังนั้นฉันอาจปล่อยให้มันเป็นแบบนี้เพื่อความชัดเจน แม้ว่าจริงมาก!
เอลเลียตแบล็กเบิร์น

@ BlueHat ดูเหมือนจะไม่สอดคล้องกันเล็กน้อยที่จะใช้สิ่งอื่นหาก แต่ไม่ใช่สิ่งอื่นในตอนท้าย
SBoss

1
@ Mehrdad ขอบคุณ! ฉันได้รวมคำตอบเก่าไว้เพียงเพราะฉันรู้สึกว่ามันละเอียดมากขึ้นและอธิบายวิธีแก้ปัญหาให้ชัดเจนขึ้นเล็กน้อย แต่โซลูชันของคุณมีขนาดเล็กกว่ามากและทำงานเหมือนกัน
Elliot Blackburn

1
ดียิ่งขึ้น (แย่กว่า):or(a, b): a ? a : b
sara

149

นี่คือวิธีแก้ปัญหาโดยไม่ต้องหรือไม่และไม่เปรียบเทียบและตัวอักษรบูลีน:

or(arg1, arg2)
  if arg1
    return arg1
  else
    return arg2

มันอาจจะไม่ได้พื้นฐานมากกว่านั้น;)


32
+1 สำหรับคำตอบที่สั้นกว่าของฉันเล็กน้อย อย่างไรก็ตามฉันถูกล่อลวงให้ทิ้ง "คนอื่น" เช่นกันเพื่อความสง่างาม
Elliot Blackburn

10
@ BlueHat แต่แล้วทั้งสองกลับจะเยื้องแตกต่างกันไป);
fredoverflow

5
ฉันต้องการที่จะได้รับ EUR แต่ละครั้งที่มีคนเปรียบเทียบบางสิ่งบางอย่างกับหรือtrue false
JensG

1
@ JensG คุณคิดว่ารายได้ของ Bill Gates มาจากไหน?
Kroltan

1
||ตัวดำเนินการJavaScript สั้น ๆ (เมื่อใช้งานในภาษาที่พิมพ์แบบไดนามิก)
แรด

108

รหัสหนึ่งบรรทัด:

return not (not arg1 and not arg2)

ไม่มีการแตกกิ่งไม่มีหรือ

ในภาษา C-based มันจะเป็น:

return !(!arg1 && !arg2);

นี่เป็นเพียงการประยุกต์ใช้กฎหมายของDe Morgan :(A || B) == !(!A && !B)


6
ฉันคิดว่าวิธีนี้เป็นทางออกที่ดีที่สุดเนื่องจาก (ในความคิดของฉัน) การif/elseสร้างนั้นเหมือนกับการใช้ OR เพียงแค่ใช้ชื่ออื่น
นิค

2
@Nick ที่ใช้ifนั้นเทียบเท่ากับความเสมอภาค โดยปกติในโค้ดเครื่อง a ifจะถูกใช้เป็นเลขคณิตตามด้วยการเปรียบเทียบกับศูนย์ด้วยการกระโดด

6
สำหรับการอ้างอิง: en.wikipedia.org/wiki/De_Morgan%27s_laws
Mephy

1
ฉันชอบวิธีนี้เพราะมันลัดวงจร IFF andลัดวงจรจึงให้ความสม่ำเสมอในหมู่ผู้ใช้งาน
Kyle Strand

1
@Snowman นั่นเป็นเรื่องจริง ฉันหมายถึงif (a) return true; else if (b) return true;ดูเหมือนว่าจะเทียบเท่าทางศีลธรรมมากกว่าหรือน้อยกว่าif (a OR b) return true;แต่มุมมองนั้นอาจเปิดรับการโต้แย้งได้
Nick

13

หากคุณมีandและnotคุณสามารถใช้กฎหมายของ DeMorgan เพื่อพลิกดูand:

if not (arg1 = False and arg2 = False)
  return True
else
  return False

... หรือ (ยิ่งง่ายขึ้น)

if arg1 = False and arg2 = False
  return false
else
  return true

...

และเนื่องจากเราทุกคนต่างก็จับจ้องอยู่ที่การเพิ่มประสิทธิภาพบางอย่างที่เกือบจะใช้ได้ตลอดเวลาตามคำสั่งของเครื่อง

return not(not arg1 and not arg2)

return arg1 ? true : arg2

ฯลฯ เป็นต้น ฯลฯ

เนื่องจากภาษาส่วนใหญ่มีเงื่อนไขและและอัตราเดิมพันเป็นตัวดำเนินการ "และ" จึงหมายถึงสาขาอยู่แล้ว

...

ถ้าคุณมีnand(ดูวิกิพีเดีย ):

return nand (nand (arg1, arg1), nand (arg2, arg2))


7
ลดความซับซ้อน:return not (not arg1 and not arg2)

@Snowman คุณควรทำคำตอบนั้นจริง ๆ เพื่อที่ฉันจะได้ลงคะแนนได้ คุณเป็นคนเดียวที่นี่ที่ไม่ได้ไปกับสาขา
Lawtonfogle

4
กำลังจะเพิ่มโซลูชัน NAND แต่คุณเอาชนะฉันได้ ทุกสิ่งควรนำมาใช้ในแง่ของ NAND
Andy

2
@Andy: จริง ๆ แล้วทุกอย่างควรกำหนดในแง่ของ NOR ;-)
Pieter Geerkens

1
ทำงานได้ดีกับnandโซลูชันที่บริสุทธิ์
AAT

13

ฟังก์ชั่น (ECMAScript)

สิ่งที่คุณต้องมีคือนิยามฟังก์ชันและการเรียกใช้ฟังก์ชัน คุณไม่ต้องการการแยกย่อยเงื่อนไขเงื่อนไขตัวดำเนินการหรือฟังก์ชันบิวด์อิน ฉันจะสาธิตการใช้งานโดยใช้ ECMAScript

อันดับแรกให้กำหนดสองฟังก์ชั่นที่เรียกว่าและtrue falseเราสามารถกำหนดพวกเขาในแบบที่เราต้องการพวกเขาเป็นแบบอย่างโดยพลการ แต่เราจะกำหนดพวกเขาในวิธีพิเศษมากซึ่งมีข้อได้เปรียบบางประการที่เราจะเห็นในภายหลัง:

const tru = (thn, _  ) => thn,
      fls = (_  , els) => els;

truเป็นฟังก์ชั่นที่มีสองพารามิเตอร์ซึ่งเพียงละเว้นอาร์กิวเมนต์ที่สองและส่งกลับค่าแรก flsเป็นฟังก์ชั่นที่มีพารามิเตอร์สองตัวที่ไม่ต้องสนใจอาร์กิวเมนต์แรกและส่งคืนพารามิเตอร์ตัวที่สอง

ทำไมเราเข้ารหัสtruและflsวิธีนี้ ด้วยวิธีนี้ฟังก์ชั่นทั้งสองไม่เพียงแสดงถึงแนวคิดทั้งสองtrueและfalseในเวลาเดียวกันพวกเขายังแสดงแนวคิดของ "ตัวเลือก" ในคำอื่น ๆ พวกเขายังเป็นif/ then/ elseแสดงออก! เราประเมินifสภาพและส่งผ่านthenบล็อกและelseบล็อกเป็นอาร์กิวเมนต์ หากเงื่อนไขประเมินtruเป็นจะส่งคืนthenบล็อกหากประเมินflsเป็นเงื่อนไขจะส่งคืนelseบล็อก นี่คือตัวอย่าง:

tru(23, 42);
// => 23

สิ่งนี้จะส่งคืน23และสิ่งนี้:

fls(23, 42);
// => 42

ผลตอบแทน42เช่นเดียวกับที่คุณคาดหวัง

มีริ้วรอย แต่:

tru(console.log("then branch"), console.log("else branch"));
// then branch
// else branch

มันพิมพ์ทั้ง then branchและelse branch! ทำไม?

มันส่งคืนค่าส่งคืนของอาร์กิวเมนต์แรก แต่ประเมินค่าอาร์กิวเมนต์ทั้งสองเนื่องจาก ECMAScript มีความเข้มงวดและมักจะประเมินอาร์กิวเมนต์ทั้งหมดไปยังฟังก์ชันก่อนเรียกฟังก์ชัน IOW: มันประเมินค่าอาร์กิวเมนต์แรกซึ่งก็คือconsole.log("then branch")ส่งคืนundefinedและมีผลข้างเคียงของการพิมพ์then branchไปยังคอนโซลและประเมินผลอาร์กิวเมนต์ที่สองซึ่งส่งกลับundefinedและพิมพ์ไปยังคอนโซลเป็นผลข้างเคียง undefinedจากนั้นก็จะส่งกลับคนแรก

ใน calcul-แคลคูลัสซึ่งการเข้ารหัสนี้ถูกประดิษฐ์ขึ้นนั่นไม่ใช่ปัญหา: calcul-แคลคูลัสนั้นบริสุทธิ์ซึ่งหมายความว่ามันไม่มีผลข้างเคียงใด ๆ ดังนั้นคุณจะไม่สังเกตเห็นว่าอาร์กิวเมนต์ที่สองได้รับการประเมินเช่นกัน นอกจากนี้ calcul-แคลคูลัสขี้เกียจ (หรืออย่างน้อยก็มักจะถูกประเมินภายใต้คำสั่งปกติ) ความหมายมันไม่ได้ประเมินอาร์กิวเมนต์ที่ไม่ต้องการ ดังนั้น IOW: ในλ-แคลคูลัสอาร์กิวเมนต์ที่สองจะไม่ถูกประเมินและถ้าเป็นเราจะไม่สังเกตเห็น

อย่างไรก็ตาม ECMAScript นั้นเข้มงวดมากเช่นจะประเมินอาร์กิวเมนต์ทั้งหมดเสมอ ดีจริงไม่ได้เสมอที่: if/ then/ elseตัวอย่างเช่นเพียงประเมินthenสาขาถ้าเงื่อนไขเป็นtrueและมีเพียงประเมินสาขาถ้าเงื่อนไขเป็นelse และเราต้องการที่จะทำซ้ำพฤติกรรมนี้กับเราfalse iffโชคดีที่แม้ว่า ECMAScript จะไม่ขี้เกียจ แต่ก็มีวิธีที่จะชะลอการประเมินผลของชิ้นส่วนของรหัส แต่วิธีเดียวกันกับที่เกือบทุกภาษาอื่นจะทำได้: ห่อไว้ในฟังก์ชั่นและถ้าคุณไม่เคยเรียกใช้ฟังก์ชั่นนั้น ไม่เคยถูกประหารชีวิต

ดังนั้นเราจึงตัดทั้งสองบล็อกในฟังก์ชันและเมื่อสิ้นสุดการเรียกฟังก์ชันที่ส่งคืน:

tru(() => console.log("then branch"), () => console.log("else branch"))();
// then branch

พิมพ์then branchและ

fls(() => console.log("then branch"), () => console.log("else branch"))();
// else branch

else branchพิมพ์

เราสามารถใช้แบบดั้งเดิมif/ then/ elseด้วยวิธีนี้:

const iff = (cnd, thn, els) => cnd(thn, els);

iff(tru, 23, 42);
// => 23

iff(fls, 23, 42);
// => 42

อีกครั้งเราจำเป็นต้องมีการตัดฟังก์ชั่นพิเศษบางอย่างเมื่อเรียกใช้iffฟังก์ชั่นและวงเล็บเรียกฟังก์ชันพิเศษในคำจำกัดความของiffด้วยเหตุผลเดียวกันกับข้างต้น:

const iff = (cnd, thn, els) => cnd(thn, els)();

iff(tru, () => console.log("then branch"), () => console.log("else branch"));
// then branch

iff(fls, () => console.log("then branch"), () => console.log("else branch"));
// else branch

orตอนนี้เรามีทั้งสองคำจำกัดความของเราสามารถดำเนินการได้ อันดับแรกเราดูที่ตารางความจริงสำหรับor: ถ้าตัวถูกดำเนินการตัวแรกเป็นความจริงผลลัพธ์ของการแสดงออกจะเหมือนกับตัวถูกดำเนินการแรก มิฉะนั้นผลลัพธ์ของนิพจน์คือผลลัพธ์ของตัวถูกดำเนินการที่สอง กล่าวโดยย่อ: ถ้าตัวถูกดำเนินการแรกคือtrueเราส่งคืนตัวถูกดำเนินการแรกมิฉะนั้นเราจะส่งคืนตัวถูกดำเนินการที่สอง:

const orr = (a, b) => iff(a, () => a, () => b);

ตรวจสอบว่ามันใช้งานได้:

orr(tru,tru);
// => tru(thn, _) {}

orr(tru,fls);
// => tru(thn, _) {}

orr(fls,tru);
// => tru(thn, _) {}

orr(fls,fls);
// => fls(_, els) {}

ที่ดี! อย่างไรก็ตามคำจำกัดความนั้นดูน่าเกลียดเล็กน้อย จำไว้truและflsทำตัวเหมือนมีเงื่อนไขด้วยตัวเองแล้วดังนั้นจึงไม่จำเป็นต้องทำiffดังนั้นจึงรวมฟังก์ชันทั้งหมดไว้ด้วย:

const orr = (a, b) => a(a, b);

ที่นั่นคุณมี: or(รวมถึงตัวดำเนินการบูลีนอื่น ๆ ) กำหนดโดยไม่มีอะไรนอกจากนิยามฟังก์ชันและการเรียกใช้ฟังก์ชันในเพียงไม่กี่บรรทัด:

const tru = (thn, _  ) => thn,
      fls = (_  , els) => els,
      orr = (a  , b  ) => a(a, b),
      nnd = (a  , b  ) => a(b, a),
      ntt = a          => a(fls, tru),
      xor = (a  , b  ) => a(ntt(b), b),
      iff = (cnd, thn, els) => cnd(thn, els)();

น่าเสียดายที่การใช้งานนี้ค่อนข้างไร้ประโยชน์: ไม่มีฟังก์ชั่นหรือตัวดำเนินการใน ECMAScript ที่ส่งคืนtruหรือflsพวกเขาทั้งหมดส่งคืนtrueหรือfalseดังนั้นเราจึงไม่สามารถใช้พวกเขากับฟังก์ชั่นของเรา แต่ยังมีอีกมากที่เราสามารถทำได้ ตัวอย่างเช่นนี่เป็นการใช้งานของรายการที่ลิงก์โดยลำพัง:

const cons = (hd, tl) => which => which(hd, tl),
      car  = l => l(tru),
      cdr  = l => l(fls);

วัตถุ (Scala)

คุณอาจสังเกตเห็นสิ่งที่แปลกประหลาด: truและflsมีบทบาทสองอย่างพวกเขาทำหน้าที่ทั้งสองเป็นค่าข้อมูลtrueและfalseแต่ในเวลาเดียวกันพวกเขายังทำหน้าที่เป็นนิพจน์เงื่อนไข พวกมันคือข้อมูลและพฤติกรรมรวมเข้าเป็นหนึ่งเดียว ... อืม ... "สิ่งของ" ... หรือ (กล้าพูด) วัตถุ !

แน่นอนtruและflsเป็นวัตถุ และหากคุณเคยใช้ Smalltalk, Self, Newspeak หรือภาษาเชิงวัตถุอื่น ๆ คุณจะสังเกตเห็นว่าพวกเขาใช้ booleans ในลักษณะเดียวกัน ฉันจะแสดงให้เห็นถึงการดำเนินการดังกล่าวใน Scala:

sealed abstract trait Buul {
  def apply[T, U <: T, V <: T](thn: ⇒ U)(els: ⇒ V): T
  def &&&(other:Buul): Buul
  def |||(other:Buul): Buul
  def ntt: Buul
}

case object Tru extends Buul {
  override def apply[T, U <: T, V <: T](thn: ⇒ U)(els: ⇒ V): U = thn
  override def &&&(other:Buul) = other
  override def |||(other:Buul): this.type = this
  override def ntt = Fls
}

case object Fls extends Buul {
  override def apply[T, U <: T, V <: T](thn: ⇒ U)(els: ⇒ V): V = els
  override def &&&(other:Buul): this.type = this
  override def |||(other:Buul) = other
  override def ntt = Tru
}

object BuulExtension {
  import scala.language.implicitConversions
  implicit def boolean2Buul(b:Boolean) = if (b) Tru else Fls
}

import BuulExtension._

(2 < 3) { println("2 is less than 3") } { println("2 is greater than 3") }
// 2 is less than 3

BTW นี้เป็นสาเหตุที่การแทนที่เงื่อนไขด้วย Polymorphism Refactoring ทำงานได้ตลอดเวลา: คุณสามารถแทนที่เงื่อนไขใด ๆ ในโปรแกรมของคุณด้วยการส่งข้อความ polymorphic เพราะในขณะที่เราเพิ่งแสดง ภาษาเช่น Smalltalk, Self และ Newspeak เป็นข้อพิสูจน์ที่มีอยู่เพราะภาษาเหล่านั้นไม่มีเงื่อนไข (พวกมันไม่มีลูป, BTW หรือโครงสร้างการควบคุมภาษาในตัวใด ๆยกเว้นการส่งข้อความแบบ polymorphic หรือการเรียกเมธอดเสมือนจริง)


การจับคู่รูปแบบ (Haskell)

นอกจากนี้คุณยังสามารถกำหนดorโดยใช้การจับคู่รูปแบบหรือบางอย่างเช่นนิยามฟังก์ชันบางส่วนของ Haskell:

True ||| _ = True
_    ||| b = b

แน่นอนการจับคู่รูปแบบเป็นรูปแบบของการดำเนินการตามเงื่อนไข แต่แล้วอีกครั้งดังนั้นการจัดส่งข้อความเชิงวัตถุ


2
วิธีการเกี่ยวกับFalse ||| False = Falseและ_ ||| _ = Trueแทน? :)
fredoverflow

3
@FredOverflow: นั่นจะต้องมีการประเมินตัวถูกดำเนินการที่ถูกต้องเสมอ โดยปกติแล้วโอเปอเรเตอร์บูลีนคาดว่าจะไม่เข้มงวดในอาร์กิวเมนต์ที่ถูกต้องหรือที่รู้จักกันในชื่อ "การลัดวงจร"
Jörg W Mittag

อ่าแน่นอน ผมรู้ว่ามีคนที่จะเป็นเหตุผลลึก :)
fredoverflow

ส่วนแรกทำให้ผมนึกถึงทันทีของชุดที่ดีเอริค Lippert เกี่ยวกับสไตล์การส่งต่อเนื่อง บริสุทธิ์โดยบังเอิญ แต่ก็ยังคงสนุก :)
Voo

1
@ JörgWMittagคำจำกัดความของ FredOverflow นั้นมีการลัดวงจรอย่างเหมาะสม ลองTrue ||| undefinedด้วยตัวเองใน ghci เพื่อดู!
Daniel Wagner

3

นี่เป็นอีกวิธีหนึ่งในการนิยาม OR หรือตัวดำเนินการเชิงตรรกะใด ๆ โดยใช้วิธีการกำหนดแบบดั้งเดิมที่สุด: ใช้ตารางความจริง

แน่นอนว่าเป็นเรื่องเล็กน้อยที่ต้องทำในภาษาระดับสูงกว่าเช่น Javascript หรือ Perl แต่ฉันเขียนตัวอย่างนี้ใน C เพื่อแสดงว่าเทคนิคนั้นไม่ได้ขึ้นอยู่กับคุณสมบัติภาษาระดับสูง:

#include <stdio.h>

int main (void) {
    // Define truth table for OR:
    int OR[2][2] = {
        {0,   // false, false
         1},  // false, true
        {1,   // true, false
         1}   // true, true
    }

    // Let's test the definition
    printf("false || false = %d\n",OR[1==2]['b'=='a']);
    printf("true || false = %d\n",OR[10==10]['b'=='a']);

    // Usage:
    if (OR[ 1==2 ][ 3==4 ]) {
        printf("at least one is true\n");
    }
    else {
        printf("both are false\n");
    }
}

คุณสามารถทำเช่นเดียวกันกับ AND, NOR, NAND, NOT และ XOR รหัสสะอาดพอที่จะดูเหมือนไวยากรณ์ซึ่งคุณสามารถทำสิ่งนี้:

if (OR[ a ][ AND[ b ][ c ] ]) { /* ... */ }

ฉันคิดว่านี่เป็นวิธีการ "บริสุทธิ์" ในแง่คณิตศาสตร์บางอย่าง OR-โอเปอเรเตอร์คือฟังก์ชั่นหลังจากทั้งหมดและตารางความจริงเป็นแก่นแท้ของฟังก์ชั่นนั้นในฐานะความสัมพันธ์และเซต ของหลักสูตรนี้สามารถเขียนในลักษณะ OO สนุกเกินไป:BinaryOperator or = new TruthTableBasedBinaryOperator(new TruthTable(false, true, true, true));
จาก

3

อีกวิธีในการแสดงตัวดำเนินการเชิงตรรกะเป็นนิพจน์เชิงเลขจำนวนเต็ม (ที่เป็นไปได้) วิธีนี้สามารถหลีกเลี่ยงการแตกแขนงมากมายสำหรับการแสดงออกของเพรดิเคตจำนวนมาก ..

ให้ True เป็น 1 ให้ False เป็น 0

หากผลรวมของทั้งสองมีค่ามากกว่า 1 จะเป็นความจริงหรือเท็จที่จะส่งคืน

boolean isOR(boolean arg1, boolean arg2){

   int L = arg1 ? 1 : 0;
   int R = arg2 ? 1 : 0;

   return (L+R) > 0;

}

6
booleanExpression ? true : falseเท่ากับbooleanExpressionเล็กน้อย
Keen

ฉันชอบวิธีการของคุณ แต่ข้อผิดพลาดง่าย ๆ ก็คือผลรวมของการขัดแย้งทั้งสองจะต้องมากกว่าศูนย์ที่จะเป็นจริงไม่มากกว่าหนึ่ง
Grant

1
return (arga+argb)>0
Grantly

1
ฉันแค่แก้ไขข้อความของคุณ รหัสของคุณสมบูรณ์แบบ แต่อาจจะอยู่ในบรรทัดเดียว: return (((arg1 ? 1 : 0)+(arg2 ? 1 : 0)) > 0); :)
Grantly

1
@SenthuSivasambu ฉันไม่คัดค้านการใช้งานของarg1 ? 1 : 0;คุณ สิ่งเหล่านี้คือนิพจน์ที่น่าเชื่อถือสำหรับการแปลงบูลีนเป็นตัวเลข เป็นเพียงข้อความสั่งคืนที่สามารถปรับโครงสร้างใหม่ได้เล็กน้อย
Keen

1

ทั้งสองรูปแบบ:

OR(arg1, arg2)
  if arg1
     return True
  else:
     return arg2

หรือ

OR(arg1, arg2)
  if arg1
     return arg1
  else:
     return arg2

มีข้อได้เปรียบเหมือนโค้ดกอล์ฟที่มีขนาดเล็กกว่าข้อเสนอแนะอื่น ๆ จนถึงขณะนี้มีสาขาน้อยกว่าหนึ่งสาขา มันไม่ได้โง่ขนาดเล็กที่เลือกลดจำนวนสาขาถ้าเรากำลังพิจารณาการสร้างดั้งเดิมที่จะใช้อย่างหนัก

นิยามของจาวาสคริปต์||จะคล้ายกับการนี้ซึ่งรวมกับวิธีการพิมพ์ของมันหลวมที่แสดงออกfalse || "abc"มีค่า"abc"และมีความคุ้มค่า42 || "abc"42

แม้ว่าคุณจะมีตัวดำเนินการเชิงตรรกะอื่น ๆ อยู่แล้วก็ตามการชอบnand(not(arg1), not(arg2))อาจมีข้อดีของการไม่แตกแขนงเลย


จุดที่ทำซ้ำคำตอบก่อนหน้าคืออะไร ( ตามที่คุณยอมรับ )
ริ้น

@ มันใกล้พอที่ฉันจะไม่ต้องกังวลถ้าฉันเห็นคำตอบนั้น แต่มันก็ยังมีบางสิ่งที่ไม่พบในพวกเขาดังนั้นฉันจึงทิ้งมันไว้
Jon Hanna

@gnat พิจารณาจริง ๆ ว่า "เรากำลังมองหาคำตอบยาว ๆ ที่ให้คำอธิบายและบริบท" ฉันมีความสุขกับคำตอบนี้แล้ว
Jon Hanna

1

นอกเหนือจากโซลูชันที่โปรแกรมไว้ทั้งหมดโดยใช้การสร้างถ้ามันเป็นไปได้ที่จะสร้างประตู OR โดยการรวมประตู NAND สามประตู หากคุณต้องการที่จะเห็นวิธีการที่จะทำในวิกิพีเดีย, คลิกที่นี่

จากนี้การแสดงออก

ไม่ [ไม่ (A และ A) และไม่ (B และ B)]

ซึ่งใช้ NOT และ AND ให้คำตอบเดียวกับ OR ขอให้สังเกตว่าการใช้ทั้ง NOT และ AND เป็นเพียงวิธีคลุมเครือในการแสดง NAND


ไม่ใช่ (A และ A) == ไม่ใช่ (A)?
ชาร์ลี

ใช่แล้ว ในบทความวิกิพีเดียเดียวกันคุณสามารถดูว่าพวกเขาลดเกต NOT ไปที่ประตู NAND ได้อย่างไร เหมือนกันสำหรับประตู AND ฉันเลือกที่จะไม่แก้ไขสูตรที่นำเสนอสำหรับประตู OR
Walter Mitty

1

คำตอบที่ดีทั้งหมดได้รับแล้ว แต่ฉันจะไม่ปล่อยให้มันหยุดฉัน

// This will break when the arguments are additive inverses.
// It is "cleverness" like this that's behind all the most amazing program errors.
or(arg1, arg2)
    return arg1 + arg2
    // Or if you need explicit conversions:
    // return (bool)((short)arg1 + (short)arg2)

อีกวิธีหนึ่งคือ:

// Since `0 > -1`, negative numbers will cause weirdness.
or(arg1, arg2)
    return max(arg1, arg2)

ฉันหวังว่าจะไม่มีใครใช้วิธีการเช่นนี้ พวกเขาอยู่ที่นี่เพียงเพื่อส่งเสริมการรับรู้ทางเลือก

ปรับปรุง:

เนื่องจากตัวเลขติดลบสามารถทำลายทั้งสองวิธีข้างต้นนี่เป็นคำแนะนำที่น่ากลัวอีกข้อหนึ่ง:

or(arg1, arg2)
    return !(!arg1 * !arg2)

นี่ใช้กฏของ DeMorganและใช้ความจริงที่*คล้ายคลึงกับ&&เวลาtrueและเมื่อfalseได้รับการปฏิบัติเหมือน1และ0ตามลำดับ (เดี๋ยวก่อนคุณกำลังบอกว่านี่ไม่ใช่โค้ดกอล์ฟใช่ไหม)

นี่คือคำตอบที่ดี:

or(arg1, arg2)
    return arg1 ? arg1 : arg2

แต่นั่นก็เหมือนกับคำตอบอื่น ๆ ที่ได้ให้ไว้แล้ว


3
วิธีการเหล่านี้มีข้อบกพร่องพื้นฐาน พิจารณา -1 + 1 สำหรับarg1+arg2-1 และ 0 สำหรับmax(arg1,arg2)ฯลฯ
ปุย

@fluffy วิธีการนี้จะถือว่าอาร์กิวเมนต์ของบูลีนเกิดขึ้นเมื่อทำงานอย่างถูกต้องกับอินพุตขยะส่วนใหญ่ ดีสำหรับคุณที่จะชี้ให้เห็นว่ายังมีขยะบางส่วนที่ก่อให้เกิดปัญหา สิ่งนี้เป็นเหตุผลว่าทำไมเราควรพยายามสร้างแบบจำลองโดเมนปัญหาที่เกิดขึ้นจริงโดยตรงที่สุด (และหลีกเลี่ยงการดำเนินการโดยความฉลาดของเราเอง) ในทางปฏิบัติ
Keen

หากคุณทำค่าบูลีนแบบ 1 บิตอย่างแท้จริงการเพิ่มจะยังใช้งานไม่ได้เนื่องจาก 1 + 1 = 0. :)
ปุย

@fluffy นั่นคือที่มาของการแปลงที่ชัดเจนไม่ว่าพวกเขาจะต้องการหรือไม่ขึ้นอยู่กับรายละเอียดของการติดตั้ง (ซึ่งเป็นสาเหตุที่เป็นความคิดที่โง่)
Keen

0

วิธีหนึ่งในการกำหนดorคือผ่านตารางการค้นหา เราสามารถทำให้ชัดเจน:

bool Or( bool a, bool b } {
  bool retval[] = {b,true}; // or {b,a};
  return retval[a];
}

เราสร้างอาร์เรย์ที่มีค่าที่ค่าส่งคืนควรมีตามaนั้นคืออะไร จากนั้นเราทำการค้นหา ใน C ++ เช่นภาษาboolเลื่อนระดับเป็นค่าที่สามารถใช้เป็นดัชนีอาเรย์ด้วยtrueการเป็น1และfalseเป็น0อยู่

จากนั้นเราสามารถขยายสิ่งนี้ไปยังการดำเนินการเชิงตรรกะอื่น ๆ :

bool And( bool a, bool b } {
  bool retval[] = {false,b}; // or {a,b};
  return retval[a];
}
bool Xor( bool a, bool b } {
  bool retval[] = {b,!b};
  return retval[a];
}

ตอนนี้ข้อเสียของสิ่งเหล่านี้ก็คือมันต้องมีสัญกรณ์คำนำหน้า

namespace operators {
  namespace details {
    template<class T> struct is_operator {};
    template<class Lhs, Op> struct half_expression { Lhs&& lhs; };
    template<class Lhs, class Op>
    half_expression< Lhs, Op > operator*( Lhs&&lhs, is_operator<Op> ) {
      return {std::forward<Lhs>(lhs)};
    }
    template<class Lhs, class Op, class Rhs>
    auto operator*( half_expression<Lhs, Op>&& lhs, Rhs&& rhs ) {
    return invoke( std::forward<Lhs>(lhs.lhs), Op{}, std::forward<Rhs>(rhs) );
    }
  }
  using details::is_operator;
}

struct or_tag {};
static const operators::is_operator<or_tag> OR;

bool invoke( bool a, or_tag, bool b ) {
  bool retval[] = {b,true};
  return retval[a];
}

และตอนนี้คุณสามารถพิมพ์true *OR* falseและใช้งานได้

เทคนิคด้านบนต้องใช้ภาษาที่รองรับการค้นหาแบบอิงอาร์กิวเมนต์และแม่แบบ คุณอาจจะทำในภาษาที่มีชื่อสามัญและ ADL

นอกเหนือจากนี้คุณสามารถขยายรายการ*OR*ด้านบนเพื่อทำงานกับชุด เพียงสร้างฟังก์ชันฟรีinvokeในเนมสเปซเดียวกันกับor_tag:

template<class...Ts>
std::set<Ts...> invoke( std::set<Ts...> lhs, or_tag, std::set<Ts...> const& rhs ) {
  lhs.insert( rhs.begin(), rhs.end() );
  return lhs;
}

และตอนนี้set *OR* setส่งคืนการรวมของทั้งสอง


0

อันนี้จำได้ถึงฟังก์ชั่น charasteristic:

or(a, b)
    return a + b - a*b

สิ่งนี้ใช้กับภาษาที่สามารถปฏิบัติกับบูลลีนเป็น (1, 0) ใช้ไม่ได้กับ Smalltalk หรือ Python เนื่องจากบูลีนเป็นคลาส ใน smalltalk พวกเขาไปไกลกว่านี้ (จะเขียนในรูปแบบของรหัสเทียม):

False::or(a)
    return a

True::or(a)
    return self

และมีสองวิธีสำหรับและ:

False::and(a)
    return self

True::and(a)
    return a

ดังนั้น "ตรรกะ" จึงใช้ได้อย่างสมบูรณ์ในคำสั่ง OP แม้ว่ามันจะเป็นคำพูดที่ละเอียด ระวังก็ไม่เลว มันสมบูรณ์แบบถ้าคุณต้องการฟังก์ชั่นที่ทำหน้าที่เหมือนโอเปอเรเตอร์คณิตศาสตร์โดยอ้างอิงจากเมทริกซ์ชนิดหนึ่ง อื่น ๆ จะใช้คิวบ์จริง (เช่นคำสั่ง Quine-McCluskey):

or = array[2][2] {
    {0, 1},
    {1, 1}
}

และคุณจะประเมินหรือ [a] [b]

ใช่ทุกตรรกะที่นี่ใช้ได้ (ยกเว้นที่โพสต์เป็นการใช้ตัวดำเนินการในภาษาหรือตัวดำเนินการ xDDDDDDDD)

แต่สิ่งที่ฉันชอบคือกฎของ DeMorgan: !(!a && !b)


0

ดูไลบรารีมาตรฐาน Swift และตรวจสอบการใช้งานทางลัดหรือทางลัดและการดำเนินการ AND ซึ่งจะไม่ประเมินตัวถูกดำเนินการที่สองหากไม่ต้องการ / อนุญาต


-2

ตรรกะนั้นถูกต้องสมบูรณ์แบบ แต่สามารถทำให้ง่ายขึ้น:

or(arg1, arg2)
  if arg1 = True
     return True
  else if arg2 = True
     return True
  else
     return False

และสันนิษฐานว่าภาษาของคุณมีตัวดำเนินการ OR ดังนั้นถ้าไม่ขัดกับจิตวิญญาณของคำถาม - ทำไมไม่

or(arg1, arg2)
  if arg1 = True or arg2 = True
     return True
  else
     return False

if arg1 = True or arg2 = True { return true } else { return false } ดีกว่า return arg1 = True or arg2 = Trueยังดีกว่าif condition then true else falseซ้ำซ้อน
Doval

4
ถามชี้เฉพาะที่ต้องการของพวกเขาคือ "โดยไม่ต้องใช้ประกอบการของตัวเอง"
ริ้น

2
อืมฉันไม่ได้พูดอะไรเลย มันเป็นสิ่งที่ฉันหมายถึง แต่คำถามไม่ได้พูดอย่างนั้นจนกว่าจะมีการแก้ไขและเธอก็ตอบว่าเป็นเช่นนั้นดังนั้นความผิดของฉันในแบบนั้น
logicNoob
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.