Cara mendefinisikan "atau" secara logis

36

Baru-baru ini, saya menemukan masalah yang mengharuskan saya untuk mendefinisikan operator "OR" yang logis secara terprogram, tetapi tanpa menggunakan operator itu sendiri.

Yang saya pikirkan adalah ini:

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

Apakah logika ini benar, atau apakah saya melewatkan sesuatu?

logicNoob
sumber
10
@gnat: Agar adil, tabel kebenaran mencantumkan output untuk setiap kombinasi input dan artikel Wikipedia memberikan deskripsi fungsi. Saya pikir apa yang OP sebenarnya tanyakan adalah bagaimana mendefinisikan logika ATAU secara terprogram tanpa menggunakan operator itu sendiri.
Blrfl
6
@ user3687688 Bisakah Anda memperjelas primitif yang diizinkan untuk digunakan?
fredoverflow
4
pertanyaan ini telah memulai spasme kolektif optimasi-mikro;)
Rob
8
Anda dapat menggunakan operator ternaryreturn arg1 ? arg1 : arg2;
Matius
4
Saya harus tahu mengapa Anda perlu mendefinisikan ulang oroperator.
Kyle Strand

Jawaban:

102

Saya akan mengatakan itu benar, tetapi tidak bisakah Anda memadatkannya menjadi sesuatu seperti ini?

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

    return false

Karena Anda melakukan atau membandingkan, saya tidak berpikir Anda benar-benar perlu memeriksa kombinasi. Itu penting jika salah satu dari mereka benar untuk mengembalikan yang benar. Kalau tidak, kami ingin mengembalikan false.

Jika Anda mencari versi yang lebih pendek yang kurang bertele-tele, ini juga akan berfungsi:

or(arg1, arg2)
    if arg1
        return arg1
    return arg2
Elliot Blackburn
sumber
6
Anda juga dapat menghapus "lain" pada baris 4 (hanya menyisakan if arg2 == true).
Dawson Toth
1
@ DawsonToth Ada banyak cara Anda dapat memutarnya, tergantung apakah Anda ingin menjadi verbose atau dipadatkan. Saya akan senang dengan yang lain jika tetapi sepertinya ini adalah pertanyaan kode semu jadi saya mungkin akan membiarkannya seperti ini untuk kejelasan. Sangat benar!
Elliot Blackburn
@ BlueHat Tampaknya sedikit tidak konsisten untuk menggunakan yang lain jika, tetapi tidak yang lain pada akhirnya.
SBoss
1
@Mehrdad, Terima kasih! Saya telah memasukkan jawaban lama kembali hanya karena saya merasa itu sedikit lebih verbose dan menjelaskan solusinya sedikit lebih jelas. Tetapi solusi Anda jauh lebih kecil dan melakukan pekerjaan yang sama.
Elliot Blackburn
1
bahkan lebih baik (lebih buruk):or(a, b): a ? a : b
sara
149

Berikut adalah solusi tanpa atau, dan, bukan, perbandingan dan literal boolean:

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

Mungkin tidak menjadi jauh lebih mendasar daripada itu;)

fredoverflow
sumber
32
+1 untuk jawaban yang sedikit lebih pendek dari saya. Namun saya tergoda untuk menjatuhkan "yang lain" juga hanya untuk keanggunan.
Elliot Blackburn
10
@BlueHat Tapi kemudian dua pengembalian akan indentasi berbeda;)
fredoverflow
5
Saya ingin mendapatkan EUR setiap kali seseorang membandingkan sesuatu dengan trueatau false.
JensG
1
@JensG Nah, dari mana menurut Anda penghasilan Bill Gates berasal?
Kroltan
1
||Singkatnya operator JavaScript (bila diterapkan dalam bahasa yang diketik secara dinamis).
badak
108

Satu baris kode:

return not (not arg1 and not arg2)

Tanpa percabangan, tidak ada ATAU.

Dalam bahasa berbasis C, itu akan menjadi:

return !(!arg1 && !arg2);

Ini hanyalah sebuah aplikasi dari hukum De Morgan :(A || B) == !(!A && !B)


sumber
6
Saya pikir pendekatan ini adalah solusi terbaik karena (menurut saya) sebuah if/elsekonstruk sama dengan menggunakan OR, hanya dengan nama yang berbeda.
Nick
2
@Nick using ifsetara dengan kesetaraan. Biasanya dalam kode mesin ifdiimplementasikan sebagai aritmatika diikuti oleh perbandingan ke nol dengan lompatan.
6
Untuk referensi: en.wikipedia.org/wiki/De_Morgan%27s_laws
Mephy
1
Saya suka pendekatan ini karena hubungan arus andpendek IFF , sehingga memberikan konsistensi di antara operator.
Kyle Strand
1
@Snowman Itu benar. Maksud saya, if (a) return true; else if (b) return true;tampaknya secara moral kurang lebih sama dengan if (a OR b) return true;, tetapi pandangan itu mungkin terbuka untuk diperdebatkan.
Nick
13

Jika Anda hanya memiliki anddan not, Anda dapat menggunakan hukum DeMorgan untuk membalik and:

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

... atau (bahkan lebih sederhana)

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

...

Dan karena kita semua tampaknya menjadi terpaku pada optimalisasi sesuatu yang hampir selalu tersedia sebagai instruksi mesin, yang bermuara pada:

return not(not arg1 and not arg2)

return arg1 ? true : arg2

dll dll dll dll

Karena sebagian besar bahasa menyediakan syarat-dan, kemungkinan besar operator "dan" tetap menyiratkan cabang.

...

Jika yang Anda miliki adalah nand(lihat wikipedia ):

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

rampok
sumber
7
Sederhanakan:return not (not arg1 and not arg2)
@Snowman Anda harus benar-benar membuat jawaban itu sehingga saya bisa mengangkatnya. Anda (saat ini) satu-satunya di sini yang tidak pergi dengan percabangan.
Lawtonfogle
4
Akan menambahkan solusi NAND, tetapi Anda mengalahkan saya untuk itu. Semuanya harus diimplementasikan dalam hal NAND.
Andy
2
@Andy: Sebenarnya, semuanya harus didefinisikan dalam hal NOR. ;-)
Pieter Geerkens
1
Kerja bagus dengan nandsolusi murni .
AAT
13

Fungsi (ECMAScript)

Yang Anda butuhkan hanyalah definisi fungsi dan panggilan fungsi. Anda tidak memerlukan fungsi percabangan, kondisional, operator atau builtin apa pun. Saya akan mendemonstrasikan implementasi menggunakan ECMAScript.

Pertama, mari kita mendefinisikan dua fungsi yang disebut truedan false. Kita dapat mendefinisikannya dengan cara apa pun yang kita inginkan, mereka sepenuhnya arbitrer, tetapi kita akan mendefinisikannya dengan cara yang sangat istimewa yang memiliki beberapa kelebihan seperti yang akan kita lihat nanti:

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

truadalah fungsi dengan dua parameter yang mengabaikan argumen kedua dan mengembalikan yang pertama. flsjuga merupakan fungsi dengan dua parameter yang mengabaikan argumen pertama dan mengembalikan yang kedua.

Mengapa kami menyandikan trudan flsdengan cara ini? Nah, dengan cara ini, kedua fungsi tidak hanya mewakili dua konsep truedan false, tidak, pada saat yang sama, mereka juga mewakili konsep "pilihan", dengan kata lain, mereka juga merupakan if/ then/ elseekspresi! Kami mengevaluasi ifkondisi dan meneruskannya thenblok dan elseblok sebagai argumen. Jika kondisi dievaluasi tru, maka akan mengembalikan thenblok, jika mengevaluasi fls, akan mengembalikan elseblok. Ini sebuah contoh:

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

Ini kembali 23, dan ini:

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

kembali 42, seperti yang Anda harapkan.

Namun, ada kerutan:

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

Ini mencetak keduanya then branch dan else branch! Mengapa?

Yah, itu mengembalikan nilai pengembalian argumen pertama, tetapi mengevaluasi kedua argumen, karena ECMAScript ketat dan selalu mengevaluasi semua argumen ke suatu fungsi sebelum memanggil fungsi. TKI: ia mengevaluasi argumen pertama console.log("then branch"), yang hanya mengembalikan undefineddan memiliki efek samping dari pencetakan then branchke konsol, dan mengevaluasi argumen kedua, yang juga mengembalikan undefineddan mencetak ke konsol sebagai efek samping. Kemudian, ia mengembalikan yang pertama undefined.

Di λ-calculus, tempat penyandian ini ditemukan, itu bukan masalah: λ-calculus murni , yang berarti tidak memiliki efek samping; karena itu Anda tidak akan pernah memperhatikan bahwa argumen kedua juga akan dievaluasi. Plus, λ-calculus malas (atau setidaknya, sering dievaluasi dalam urutan normal), artinya, itu tidak benar-benar mengevaluasi argumen yang tidak diperlukan. Jadi, TKI: dalam λ-calculus argumen kedua tidak akan pernah dievaluasi, dan jika ya, kami tidak akan melihat.

Namun, ECMAScript ketat , yaitu selalu mengevaluasi semua argumen. Well, sebenarnya, tidak selalu: yang if/ then/ else, misalnya, hanya mengevaluasi thencabang jika kondisi truedan hanya mengevaluasi elsecabang jika kondisifalse . Dan kami ingin mereplikasi perilaku ini dengan kami iff. Untungnya, meskipun ECMAScript tidak malas, ia memiliki cara untuk menunda evaluasi sepotong kode, dengan cara yang sama hampir setiap bahasa lainnya: membungkusnya dalam suatu fungsi, dan jika Anda tidak pernah memanggil fungsi itu, kode tersebut akan tidak pernah dieksekusi.

Jadi, kami membungkus kedua blok dalam suatu fungsi, dan pada akhirnya memanggil fungsi yang dikembalikan:

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

cetakan then branchdan

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

cetakan else branch .

Kita bisa menerapkan cara tradisional if/ then/ elseini:

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

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

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

Sekali lagi, kita memerlukan beberapa pembungkus fungsi tambahan saat memanggil ifffungsi dan kurung fungsi panggilan ekstra dalam definisi iff, untuk alasan yang sama seperti di atas:

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

Sekarang kita memiliki dua definisi tersebut, kita dapat menerapkannya or. Pertama, kita melihat tabel kebenaran or: jika operan pertama adalah benar, maka hasil dari ekspresi sama dengan operan pertama. Kalau tidak, hasil dari ekspresi adalah hasil dari operan kedua. Singkatnya: jika operan pertama adalah true, kami mengembalikan operan pertama, jika tidak, kami mengembalikan operan kedua:

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

Mari kita periksa apakah itu berfungsi:

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

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

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

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

Besar! Namun, definisi itu terlihat agak jelek. Ingat, trudan flssudah bertindak seperti bersyarat sendiri, jadi benar-benar tidak perlu iff, dan dengan demikian semua fungsi itu membungkus sama sekali:

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

Itu dia: or(ditambah operator boolean lainnya) yang didefinisikan dengan definisi fungsi dan panggilan fungsi hanya dalam beberapa baris:

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)();

Sayangnya, implementasi ini agak tidak berguna: tidak ada fungsi atau operator dalam ECMAScript yang mengembalikan truatau fls, mereka semua kembali trueatau false, jadi kami tidak dapat menggunakannya dengan fungsi kami. Tapi masih banyak yang bisa kita lakukan. Misalnya, ini adalah implementasi dari daftar yang terhubung sendiri:

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

Objek (Scala)

Anda mungkin telah memperhatikan sesuatu yang aneh: trudan flsmemainkan peran ganda, mereka bertindak baik sebagai nilai data truedan false, tetapi pada saat yang sama, mereka juga bertindak sebagai ekspresi kondisional. Mereka adalah data dan perilaku , yang digabungkan menjadi satu ... uhm ... "benda" ... atau (berani saya katakan) objek !

Memang, trudan flsbenda. Dan, jika Anda pernah menggunakan Smalltalk, Self, Newspeak atau bahasa berorientasi objek lainnya, Anda akan memperhatikan bahwa mereka mengimplementasikan boolean dengan cara yang persis sama. Saya akan menunjukkan implementasi seperti ini di sini di 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 ini adalah alasan Ganti Kondisional Dengan Polimorfisme Refactoring selalu berfungsi: Anda selalu dapat mengganti setiap dan setiap kondisional dalam program Anda dengan pengiriman pesan polimorfik, karena seperti yang baru saja kami tunjukkan, pengiriman pesan polimorfik dapat menggantikan kondisional dengan hanya mengimplementasikannya. Bahasa seperti Smalltalk, Self dan Newspeak adalah bukti keberadaan itu, karena bahasa-bahasa itu bahkan tidak memiliki persyaratan. (Mereka juga tidak memiliki loop, BTW, atau benar - benar segala jenis struktur kontrol bawaan bahasa kecuali untuk pengiriman pesan polimorfik alias panggilan metode virtual.)


Pencocokan Pola (Haskell)

Anda juga bisa mendefinisikan ormenggunakan pencocokan pola, atau sesuatu seperti definisi fungsi parsial Haskell:

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

Tentu saja, pencocokan pola adalah bentuk eksekusi bersyarat, tetapi sekali lagi, begitu juga pengiriman pesan berorientasi objek.

Jörg W Mittag
sumber
2
Bagaimana False ||| False = Falsedan _ ||| _ = Truesebaliknya? :)
fredoverflow
3
@ FredOverflow: Itu akan mengharuskan selalu mengevaluasi operan yang tepat. Biasanya operator Boolean diharapkan tidak ketat dalam argumen kanan mereka alias "korsleting".
Jörg W Mittag
Ah, tentu saja. Saya tahu pasti ada alasan yang lebih dalam :)
fredoverflow
Bagian pertama mengingatkan saya segera pada seri hebat Eric Lippert tentang kelanjutan gaya lewat . Benar-benar kebetulan tapi tetap menyenangkan :)
Voo
1
@ JörgWMittag Definisi FredOverflow adalah hubungan arus pendek yang tepat. Coba True ||| undefinedsendiri dalam ghci untuk melihat!
Daniel Wagner
3

Berikut cara lain untuk mendefinisikan OR, atau memang operator logis, menggunakan cara paling tradisional untuk mendefinisikannya: gunakan tabel kebenaran.

Ini tentu saja cukup sepele untuk dilakukan dalam bahasa tingkat yang lebih tinggi seperti Javascript atau Perl tetapi saya menulis contoh ini dalam C untuk menunjukkan bahwa teknik ini tidak tergantung pada fitur bahasa tingkat tinggi:

#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");
    }
}

Anda dapat melakukan hal yang sama dengan AND, NOR, NAND, NOT dan XOR. Kode ini cukup bersih sehingga terlihat seperti sintaksis sehingga Anda dapat melakukan hal-hal seperti ini:

if (OR[ a ][ AND[ b ][ c ] ]) { /* ... */ }
Slebetman
sumber
Saya pikir ini adalah pendekatan "paling murni" dalam pengertian matematika tertentu. Operator OR adalah fungsi, dan tabel kebenaran adalah esensi dari fungsi itu sebagai relasi dan himpunan. Tentu saja ini dapat ditulis dengan cara OO yang lucu juga:BinaryOperator or = new TruthTableBasedBinaryOperator(new TruthTable(false, true, true, true));
DATANG DARI
3

Cara lain untuk mengekspresikan operator logis sebagai ekspresi aritmatika integer (jika memungkinkan). Cara ini dapat menghindari banyak percabangan untuk ekspresi yang lebih besar dari banyak predikat.

Biarkan Benar menjadi 1 Biarkan Salah menjadi 0

jika penjumlahan keduanya lebih besar dari 1 maka benar atau salah akan dikembalikan.

boolean isOR(boolean arg1, boolean arg2){

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

   return (L+R) > 0;

}
Senthu Sivasambu
sumber
6
booleanExpression ? true : falsesepele sama dengan booleanExpression.
Tertarik
Saya suka metodologi Anda, tetapi kesalahan sederhana adalah bahwa jumlah kedua argumen harus lebih besar dari ZERO untuk menjadi kenyataan, tidak lebih dari SATU.
Grantly
1
return (arga+argb)>0
Grantly
1
Saya hanya memperbaiki teks Anda. Kode Anda sempurna, tetapi bisa dalam satu baris: return (((arg1 ? 1 : 0)+(arg2 ? 1 : 0)) > 0); :)
Grably
1
@ SenthuSivasambu Saya tidak keberatan dengan penggunaan Anda terhadap arg1 ? 1 : 0;. Itu adalah ekspresi yang dapat diandalkan untuk mengubah Boolean menjadi angka. Hanya pernyataan pengembalian yang dapat dengan mudah dire-reforasi.
Tertarik
1

Dua bentuk:

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

ATAU

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

Memiliki serta keuntungan seperti kode golf menjadi sedikit lebih kecil dari saran lainnya sejauh ini, satu cabang kurang. Bahkan tidak sebodoh mikro-opt untuk mengurangi jumlah cabang jika kita mempertimbangkan penciptaan primitif yang karenanya akan sangat banyak digunakan.

Definisi Javascript ||mirip dengan ini, yang dikombinasikan dengan pengetikan yang longgar berarti bahwa ekspresi false || "abc"memiliki nilai "abc"dan 42 || "abc"memiliki nilai 42.

Meskipun jika Anda sudah memiliki operator logis lain maka suka nand(not(arg1), not(arg2))mungkin memiliki keuntungan tanpa percabangan sama sekali.

Jon Hanna
sumber
apa gunanya mengulangi jawaban sebelumnya ( seperti yang Anda akui )?
nyamuk
@gnat sudah cukup dekat sehingga saya tidak akan repot kalau saya melihat jawaban itu, tetapi masih ada sesuatu yang tidak ditemukan di salah satu dari mereka, jadi saya meninggalkannya.
Jon Hanna
@gnat, sebenarnya mempertimbangkan "Kami mencari jawaban panjang yang memberikan beberapa penjelasan dan konteks." Saya lebih senang dengan jawaban ini sekarang.
Jon Hanna
1

Selain semua solusi yang diprogram menggunakan if build, dimungkinkan untuk membangun gerbang OR dengan menggabungkan tiga gerbang NAND. Jika Anda ingin melihat bagaimana melakukannya di wikipedia, klik di sini .

Dari sini, ungkapan,

BUKAN [BUKAN (A DAN A) DAN BUKAN (B DAN B)]

yang menggunakan BUKAN dan DAN memberikan jawaban yang sama dengan ATAU. Perhatikan bahwa penggunaan BUKAN dan DAN hanyalah cara yang tidak jelas untuk mengekspresikan NAND.

Walter Mitty
sumber
BUKAN (A DAN A) == TIDAK (A)?
Charlie
Ya persis. Dalam artikel wikipedia yang sama, Anda dapat melihat bagaimana mereka mengurangi gerbang BUKAN ke gerbang NAND. Sama untuk gerbang AND. Saya memilih untuk tidak mengedit formula yang disajikan untuk gerbang OR.
Walter Mitty
1

Semua jawaban yang baik telah diberikan. Tetapi saya tidak akan membiarkan itu menghentikan saya.

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

Kalau tidak:

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

Saya harap tidak ada yang benar-benar menggunakan pendekatan seperti ini. Mereka ada di sini hanya untuk mempromosikan kesadaran akan alternatif.

Memperbarui:

Karena angka negatif dapat mematahkan kedua pendekatan di atas, berikut ini adalah saran buruk lainnya:

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

Ini hanya menggunakan Hukum DeMorgan dan menyalahgunakan fakta yang *mirip dengan &&kapan truedan falsediperlakukan seperti 1dan 0masing - masing. (Tunggu, maksudmu ini bukan kode golf?)

Inilah jawaban yang layak:

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

Tapi itu pada dasarnya identik dengan jawaban lain yang sudah diberikan.

Tajam
sumber
3
Pendekatan-pendekatan ini secara mendasar cacat. Pertimbangkan -1 + 1 untuk arg1+arg2, -1 dan 0 untuk max(arg1,arg2), dll
fluffy
@ Fluffy Pendekatan ini mengasumsikan argumen Boolean, dan kemudian bekerja dengan benar dengan sebagian besar jenis input sampah. Baik Anda menunjukkan bahwa masih ada beberapa sampah yang menghasilkan masalah. Hal semacam inilah yang menjadi alasan mengapa kita harus berusaha memodelkan domain masalah aktual secara langsung (dan menghindari terbawa oleh kepintaran kita sendiri) dalam praktiknya.
Tertarik
Jika Anda melakukan nilai boolean 1-bit murni, maka penambahan masih tidak berfungsi, karena 1 +1 = 0. :)
fluffy
@fluffy Di situlah konversi eksplisit masuk. Diperlukan atau tidaknya bergantung pada detail implementasi (itulah sebabnya ini ide yang konyol).
Tertarik
0

Salah satu cara untuk mendefinisikan oradalah melalui tabel pencarian. Kita dapat membuat ini eksplisit:

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

kami membuat array dengan nilai-nilai yang seharusnya memiliki nilai pengembalian tergantung pada apa a. Lalu kami melakukan pencarian. Dalam bahasa seperti C ++, boolmempromosikan ke nilai yang dapat digunakan sebagai indeks array, dengan truebeing 1dan falsebeing 0.

Kami kemudian dapat memperluas ini ke operasi logis lainnya:

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];
}

Sekarang kelemahan dari semua ini adalah itu membutuhkan notasi awalan.

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];
}

dan sekarang kamu bisa mengetik true *OR* false dan berfungsi.

Teknik di atas membutuhkan bahasa yang mendukung pencarian bergantung argumen, dan template. Anda mungkin dapat melakukannya dalam bahasa dengan obat generik dan ADL.

Sebagai tambahan, Anda dapat memperpanjang di *OR*atas untuk bekerja dengan set. Cukup buat fungsi gratis invokedi namespace yang sama dengan 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;
}

dan sekarang set *OR* setmengembalikan penyatuan keduanya.

Yakk
sumber
0

Yang ini mengingatkan saya pada fungsi charasteristic:

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

Ini hanya berlaku untuk bahasa yang dapat memperlakukan boolean sebagai (1, 0). Tidak berlaku untuk Smalltalk atau Python karena boolean adalah kelas. Dalam smalltalk mereka melangkah lebih jauh (ini akan ditulis dalam semacam kodesemu):

False::or(a)
    return a

True::or(a)
    return self

Dan ada dua metode untuk dan:

False::and(a)
    return self

True::and(a)
    return a

Jadi "logika" ini benar-benar valid dalam pernyataan OP, meskipun itu verbose. Waspadalah, itu tidak buruk. Ini sempurna jika Anda memerlukan fungsi yang bertindak seperti operator matematika berdasarkan, katakanlah, semacam matriks. Orang lain akan menerapkan kubus yang sebenarnya (seperti pernyataan Quine-McCluskey):

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

Dan Anda akan mengevaluasi atau [a] [b]

Jadi ya, setiap logika di sini valid (kecuali yang diposting menggunakan operator OR bahasa xDDDDDDDD).

Tapi yang paling saya sukai adalah hukum DeMorgan: !(!a && !b)

Luis Masuelli
sumber
0

Lihatlah perpustakaan standar Swift dan periksa penerapan pintas ATAU dan pintas DAN operasi, yang tidak mengevaluasi operan kedua jika tidak diperlukan / diizinkan.

gnasher729
sumber
-2

Logikanya sangat benar, tetapi dapat disederhanakan:

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

Dan mungkin bahasa Anda memiliki operator OR jadi - kecuali itu bertentangan dengan semangat pertanyaan - mengapa tidak

or(arg1, arg2)
  if arg1 = True or arg2 = True
     return True
  else
     return False
Julia Hayward
sumber
if arg1 = True or arg2 = True { return true } else { return false }Lebih baik lagi return arg1 = True or arg2 = True,. if condition then true else falseberlebihan.
Doval
4
Penanya secara khusus menunjukkan bahwa persyaratan mereka adalah "tanpa menggunakan operator itu sendiri"
Agas
2
Um, saya tidak mengatakan hal semacam itu. Itu agak seperti apa yang saya maksudkan, tetapi pertanyaan itu tidak mengatakan sampai itu diedit, dan dia menjawabnya demikian, jadi salah saya pada yang itu.
logicNoob