Logika untuk menguji bahwa 3 dari 4 Benar

163

Saya ingin kembali Truejika dan hanya jika 3 dari 4 nilai boolean benar.

Yang paling dekat yang saya dapatkan adalah (x ^ y) ^ (a ^ b):

Apa yang harus saya lakukan?

Simon Kuang
sumber
10
Hmm, satu-satunya cara saya bisa memikirkan tanpa rumus matematika adalah dengan menggunakan hitungan. Pertanyaan bagus! :)
Saya Cavic
10
Gagasan Anda tidak buruk, tetapi Anda harus mengambil negasinya: not a ^ not b ^ not c ^ not dbenar ketika salah satu dari nilai yang dinegasikan itu benar. Ini berarti, dari nilai-nilai asli, tepatnya satu itu salah.
Ingo
23
Apa masalah Anda yang sebenarnya di balik detail ini?
Wolf
5
@Ingo bukan a ^ bukan b ^ tidak c ^ tidak d mengembalikan benar di mana hanya satu yang salah DAN di mana 3 adalah salah.
NameSpace
9
Solusi non-hitung yang jelas adalah (!a&&b&&c&&d) || (a&&!b&&c&&d) || (a&&b&&!c&&d) || (a&&b&&c&&!d).
Jason C

Jawaban:

248

Saya sarankan menulis kode dengan cara yang menunjukkan apa yang Anda maksud. Jika Anda ingin 3 nilai menjadi benar, tampaknya wajar bagi saya bahwa nilai 3 muncul di suatu tempat.

Misalnya, di C++:

if ((int)a + (int)b + (int)c + (int)d == 3)
    ...

Ini didefinisikan dengan baik dalam C++: yang standard (§4.7/4)menunjukkan bahwa konversi booluntuk intmemberikan nilai yang diharapkan 0 atau 1.

Di Java dan C #, Anda dapat menggunakan konstruk berikut:

if ((a?1:0) + (b?1:0) + (c?1:0) + (d?1:0) == 3)
    ...
sam hocevar
sumber
23
Ini jawaban yang bagus. Ini terlihat seperti kasus X / Y itu. "Dia ingin melakukan X menggunakan Y, tetapi tidak tahu bagaimana melakukan Y. Alih-alih bertanya X, dia bertanya Y." Kecuali jika dia mendesain rangkaian logika atau sesuatu seperti itu (dan kemudian dia akan berada di situs yang salah), cara terbaik untuk melakukan ini adalah dengan cara yang dapat dibaca .
Mungkin
2
@NothingsImpossible Tidak ada yang XY tentang pertanyaan itu. Ini adalah pertanyaan yang jelas dan mudah untuk memecahkan masalah yang cukup umum dalam pemrograman. Y tidak relevan.
Ярослав Рахматуллин
Terima kasih! Ini benar-benar apa yang saya dimaksudkan untuk dilakukan, tetapi ide saya begitu canggung bahwa saya meraih logika boolean.
Simon Kuang
3
if (!!a + !!b + !!c + !!d == 3)lebih mudah untuk menulis, walaupun saya tidak tahu apakah kompiler mengoptimalkan ini atau tidak
phuclv
2
Perhatikan bahwa dalam c ++ gips dari bool ke int tidak diperlukan.
PlasmaHH
90

# 1: Menggunakan operasi percabangan?: 3 atau 4

A ^ B ? C & D : ( C ^ D ) & A

# 2 Tanpa Cabang, 7 operasi

(A ^ B ^ C ^ D) & ((A & B) | (C & D))

Kembali ketika saya gunakan untuk profil segalanya, saya menemukan solusi non-cabang agak lebih cepat operasi-untuk-operasi karena CPU dapat memprediksi jalur kode yang lebih baik, dan menjalankan lebih banyak operasi secara bersamaan. Ada sekitar 50% lebih sedikit pekerjaan dalam pernyataan percabangan di sini.

NameSpace
sumber
18
+1 - sementara jawaban lain lebih baik untuk sebagian besar bahasa pemrograman, # 2 Anda adalah jawaban terbaik dalam logika boolean murni.
Brilliand
2
Tabel kebenaran Wolframalpha untuk # 2
Sawny
68

Jika ini Python, saya akan menulis

if [a, b, c, d].count(True) == 3:

Atau

if [a, b, c, d].count(False) == 1:

Atau

if [a, b, c, d].count(False) == True:
# In Python True == 1 and False == 0

Atau

print [a, b, c, d].count(0) == 1

Atau

print [a, b, c, d].count(1) == 3

Atau

if a + b + c + d == 3:

Atau

if sum([a, b, c, d]) == 3:

Semua ini bekerja, karena Boolean adalah subclass dari integer dengan Python.

if len(filter(bool, [a, b, c, d])) == 3:

Atau, terinspirasi oleh trik yang rapi ini ,

data = iter([a, b, c, d])
if not all(data) and all(data):
thethourtheye
sumber
17
+1 Ini menyelesaikan masalah dengan menerjemahkannya dengan benar ke Python.
Wolf
Ini sedikit berbahaya karena orang dapat mengembalikan bilangan bulat bukan nol dalam konteks boolean dengan python. C trik lama bekerja di python juga: a=5;not not a == 1. Kerugian dari tidak memiliki tipe boolean nyata.
Voo
@Vo Kami juga punya bool:)
thefourtheye
@thefourtheye Ah ya benar, jauh lebih bagus daripada trik negasi ganda / retas.
Voo
1
Atau ... atau .... atau .... Seharusnya ada satu - dan lebih disukai hanya satu - cara yang jelas untuk melakukannya. : - / :-)
rz.
53

Bentuk normal yang panjang tapi sangat sederhana, (disjuntive):

 (~a & b & c & d) | (a & ~b & c & d) | (a & b & ~c & d) | (a & b & c & ~d)

Ini mungkin disederhanakan tetapi itu membutuhkan lebih banyak pemikiran: P

Gastón Bengolea
sumber
2
@Ben yang hanya memberi Anda berbagai bentuk normal, yang sudah ada dalam (DNF).
Bersepeda
8
Bagaimana dengan (a & b & (c ^ d)) | ((a ^ b) & c & d)?
user253751
2
Ya, @immibis, menurut Wolfram Alpha DNF-nya adalah rumus yang saya tulis sehingga fungsi booleannya sama.
Gastón Bengolea
2
+1 karena saya pikir seseorang yang membaca kode akan memahami apa yang dicoba lebih cepat daripada dengan jawaban lain.
Boluc Papuccuoglu
34

Tidak yakin itu lebih sederhana, tapi mungkin.

((x xor y) and (a and b)) or ((x and y) and (a xor b))

Karl Kieninger
sumber
1
Sial! Mereka seharusnya memberi opsi multi-suara jawaban! Terutama menggunakan wolfram alpha untuk membuktikan jawaban Anda benar adalah hal yang sangat bagus!
Durai Amuthan.H
22

Jika Anda ingin menggunakan logika ini dalam bahasa pemrograman, saran saya adalah

bool test(bool a, bool b, bool c, bool d){
    int n1 = a ? 1 : 0;
    int n2 = b ? 1 : 0;
    int n3 = c ? 1 : 0;
    int n4 = d ? 1 : 0;

    return n1 + n2 + n3 + n4 == 3;
}

Atau jika Anda mau, Anda bisa meletakkan semua ini dalam satu baris:

return (a ? 1 : 0) + (b ? 1 : 0) + (C ? 1 : 0) + (d ? 1 : 0) == 3;

Anda juga dapat menggeneralisasi masalah ini ke n of m :

bool test(bool *values, int n, int m){
    int sum = 0;
    for(int i = 0; i < m; i += 1){
        sum += values[i] ? 1 : 0;
    }
    return sum == n;
}
kodok
sumber
12
Kalahkan aku untuk itu. Keterbacaan mengalahkan kepintaran, setiap saat. +1
MikeTheLiar
20

Jawaban ini tergantung pada sistem representasi, tetapi jika 0 adalah satu-satunya nilai yang ditafsirkan sebagai salah, dan not(false)selalu mengembalikan nilai numerik yang sama, maka not(a) + not(b) + not(c) + not(d) = not(0)harus melakukan trik.

MattClarke
sumber
18

Perlu diingat bahwa SO jika untuk pertanyaan pemrograman, bukan hanya masalah logis, jawabannya jelas tergantung pada pilihan bahasa pemrograman. Beberapa bahasa mendukung fitur yang tidak biasa bagi orang lain.

Misalnya, dalam C ++ Anda dapat menguji kondisi Anda dengan:

(a + b + c + d) == 3

Ini harus menjadi cara tercepat untuk melakukan pemeriksaan dalam bahasa yang mendukung konversi otomatis (level rendah) dari tipe boolean ke integer. Tetapi sekali lagi, tidak ada jawaban umum untuk masalah itu.

GOTO 0
sumber
2
Ini adalah jawaban yang akan saya posting. Satu hal yang perlu ditambahkan, tergantung pada bahasa pemrograman yang digunakan, jawaban yang Anda inginkan adalah -3. Dalam VB, True = -1.
Tom Collins
11
((a xor b) xor (c xor d)) and ((a or b) and (c or d))

Ekspresi pertama mencari 1 atau 3 truedari 4. Yang kedua menghilangkan 0 atau 1 (dan kadang-kadang 2) truedari 4.

durum
sumber
11

Java 8, memfilter nilai palsu, dan menghitung nilai sebenarnya yang tersisa:

public static long count(Boolean... values) {
    return Arrays.stream(values).filter(t -> t).count();
}

Maka Anda dapat menggunakannya sebagai berikut:

if (3 == count(a, b, c, d)) {
    System.out.println("There... are... THREE... lights!");
}

Mudah generalizes untuk memeriksa ndari mitem menjadi benar.

David Conrad
sumber
11

Untuk memeriksa setidaknya nsemua Booleanitu benar, (n harus kurang dari atau sama dengan jumlah total Boolean: p)

if (((a ? 1:0) + (b ? 1:0 ) + (c ? 1:0) + (d ? 1:0 )) >= n) {
    // do the rest
}

Sunting : Setelah komentar @ Cruncher

Untuk memeriksa 3 booleandari 4

if (((a ? 1:0) + (b ? 1:0 ) + (c ? 1:0) + (d ? 1:0 )) == 3) {
    // do the rest
}

Yang lainnya :

((c & d) & (a ^ b)) | ((a & b) & (c ^ d))( Detail )

Bukan bug
sumber
OP ingin tepat n, setidaknya n. Tapi itu perubahan mudah dari solusi ini
Cruncher
2
@ Serigala pertanyaan itu milik StackUnderflow.com: p
Bukan bug
10

Inilah cara Anda bisa menyelesaikannya dalam C # dengan LINQ:

bool threeTrue = new[] { a, b, x, y }.Count(x => x) == 3;
Tim S.
sumber
10

Itu adalah fungsi Boolean simetris S₃(4). Fungsi Boolean simetris adalah fungsi boolean yang hanya bergantung pada jumlah input yang ditetapkan, tetapi tidak bergantung pada input mana yang mereka inputkan. Knuth menyebutkan fungsi jenis ini di bagian 7.1.2 di Volume 4 dari The Art of Computer Programming.

S₃(4) dapat dihitung dengan 7 operasi sebagai berikut:

(x && y && (a || b)) ^ ((x || y) && a && b)

Knuth menunjukkan bahwa ini optimal, artinya Anda tidak dapat melakukan ini dalam kurang dari 7 operasi menggunakan operator normal: &&, || , ^, <,dan >.

Namun jika Anda ingin menggunakan ini dalam bahasa yang menggunakan 1benar dan 0salah, Anda juga dapat menggunakan tambahan dengan mudah:

x + y + a + b == 3

yang membuat niat Anda cukup jelas.

Paul
sumber
9
(a && b && (c xor d)) || (c && d && (a xor b))

Dari sudut pandang logika murni inilah yang saya temukan.

Dengan prinsip lubang merpati, jika tepat 3 benar, maka a dan b benar, atau c dan d benar. Maka itu hanya masalah anding masing-masing kasus dengan tepat satu dari yang lain 2.

Tabel kebenaran Wolfram

Cruncher
sumber
Ini setara dengan solusi kedua NameSpace.
Brilliand
@Brilliand Sepertinya berbeda dengan saya. Xor-nya semuanya bersama-sama untuk mendapatkan semua 3 atau 1, kemudian mengecualikan yang dengan 1 dengan membutuhkan setidaknya satu dari 2 kelompok yang berbeda. (diringkas sebagai 1 atau 3 dan setidaknya 2). Milik saya memerlukan keduanya dari salah satu kelompok yang berbeda, dan kemudian tepat satu dari kelompok lain.
Cruncher
Jika Anda berarti setara dalam arti itu mine <=> hismaka saya tidak tahu harus berkata apa karena ini yang diharapkan.
Cruncher
Saya kira maksud saya bahwa jawaban ini baik dengan cara yang persis sama dengan solusi kedua NameSpace yang baik, tanpa menambahkan sesuatu yang baru yang tidak dicakup oleh jawaban NameSpace. Yah, saya akan tetap memilih.
Brilliand
8

Jika Anda menggunakan alat visualisasi logika seperti Karnaugh Maps, Anda melihat bahwa ini adalah masalah di mana Anda tidak dapat menghindari istilah logika penuh sesak jika Anda ingin menulisnya dalam satu baris if (...). Lopina sudah menunjukkannya, tidak mungkin untuk menulisnya dengan lebih sederhana. Anda dapat sedikit faktor, tetapi akan tetap sulit dibaca untuk Anda DAN untuk mesin.

Menghitung solusi tidak buruk dan mereka menunjukkan apa yang benar-benar Anda cari. Cara Anda menghitung secara efisien tergantung pada bahasa pemrograman Anda. Solusi array dengan Python oder LinQ bagus untuk dilihat, tetapi berhati-hatilah, ini PERLAHAN. Wolf's (a + b + x + y) == 3 akan bekerja dengan baik dan cepat, tetapi hanya jika bahasa Anda menyamakan "true" dengan 1. Jika "true" diwakili oleh -1, Anda harus menguji -3: )

Jika bahasa Anda menggunakan boolean sejati, Anda dapat mencoba memprogramnya secara eksplisit (saya menggunakan! = Sebagai tes XOR):

if (a)
{
    if (b)
        return (x != y);    // a,b=true, so either x or y must be true
    else
        return (x && y);     // a=true, b=false, so x AND y must be true
}
else
{
    if (b)
        return (x && y);    // a=false, b=true, so x and y must be true
    else
        return false;       // a,b false, can't get 3 of 4
}

"x! = y" hanya berfungsi jika x, y adalah tipe boolean. Jika mereka adalah tipe lain di mana 0 salah dan yang lainnya benar, ini bisa gagal. Kemudian gunakan boolean XOR, atau ((bool) x! = (Bool) y), atau tulis "jika (x) kembali (y == salah) lain kembali (y == benar);", yang sedikit lebih bekerja untuk komputer.

Jika bahasa pemrograman Anda menyediakan operator ternary?:, Anda dapat mempersingkatnya menjadi

if (a)
    return b ? (x != y) : (x && y);
else
    return b ? (x && y) : false;

yang membuat sedikit mudah dibaca, atau memotongnya secara agresif

return a ? (b ? (x != y) : (x && y)) : (b ? (x && y) : false);

Kode ini melakukan persis tiga tes logika (keadaan a, keadaan b, perbandingan x dan y) dan harus lebih cepat daripada sebagian besar jawaban lain di sini. Tapi Anda perlu berkomentar, atau Anda tidak akan memahaminya setelah 3 bulan :)

Rolf
sumber
8

Ada banyak jawaban bagus di sini; berikut adalah formulasi alternatif yang belum diposting oleh orang lain:

 a ? (b ? (c ^ d) : (c && d)) : (b && c && d)
Alex D
sumber
Terima kasih atas jawaban Anda, tetapi bisakah Anda menambahkan komentar tentang cara kerjanya? Terima kasih.
Deanna
(Maaf memilih Anda, saya diberikan sebagai audit peninjauan. Setidaknya saya lulus .. :))
Deanna
7

Mirip dengan jawaban pertama, tetapi Java murni:

int t(boolean b) {
    return (b) ? 1 : 0;
}

if (t(x) + t(y) + t(a) + t(b) == 3) return true;
return false;

Saya lebih suka menghitungnya sebagai bilangan bulat karena membuat kode lebih mudah dibaca.

La-comadreja
sumber
7

Dalam Python , untuk melihat berapa banyak dari elemen yang dapat diubah Benar, gunakan sum(cukup mudah):

Mempersiapkan

import itertools

arrays = list(itertools.product(*[[True, False]]*4))

Tes Aktual

for array in arrays:
    print(array, sum(array)==3)

Keluaran

(True, True, True, True) False
(True, True, True, False) True
(True, True, False, True) True
(True, True, False, False) False
(True, False, True, True) True
(True, False, True, False) False
(True, False, False, True) False
(True, False, False, False) False
(False, True, True, True) True
(False, True, True, False) False
(False, True, False, True) False
(False, True, False, False) False
(False, False, True, True) False
(False, False, True, False) False
(False, False, False, True) False
(False, False, False, False) False
Aaron Hall
sumber
5

Jika Anda mencari solusi on-the-paper (non-pemrograman), maka K-maps dan algoritma Quine-McCluskey adalah yang Anda cari, mereka membantu Anda memperkecil fungsi boolean Anda.

Dalam kasus Anda, hasilnya adalah

y = (x̄3 ^ x2 ^ x1 ^ x0) ∨ (x3 ^ x̄2 ^ x1 ^ x0) ∨ (x3 ^ x2 ^ x̄1 ^ x0) ∨ (x3 ^ x2 ^ x1 ^ x̄0)

Jika Anda ingin melakukan ini secara program, jumlah variabel yang tidak tetap dan "ambang" kustom, maka cukup iterasi melalui daftar nilai boolean dan menghitung kejadian "benar" cukup sederhana dan mudah.

ioreskovic
sumber
1
Apa arti bar overhead? Saya perhatikan itu bergerak ke bawah daftar.
NameSpace
3
@NameSpace Ini adalah salah satu dari IMO yang terlalu banyak digunakan orang untuk menyatakan "tidak".
5

Saya ingin mengembalikan true jika dan hanya jika 3 dari 4 nilai boolean benar.

Dengan 4 nilai boolean, a, b, x, y, tugas ini diterjemahkan ke dalam pernyataan C berikut:

return (a+b+x+y) == 3;
Serigala
sumber
1
Perangkap yang bagus. Ini mengasumsikan truesama dengan 1. Ini tidak benar (tidak ada kata pun dimaksudkan) dalam semua bahasa / kasus. blogs.msdn.com/b/oldnewthing/archive/2004/12/22/329884.aspx
JensG
@JensG Anda benar: Saya membuat asumsi ini eksplisit. Terima kasih :)
Wolf
4
((a^b)^(x^y))&((a|b)&(x|y))

adalah apa yang kamu inginkan. Pada dasarnya saya mengambil kode Anda dan menambahkan memeriksa apakah 3 benar dan 3 tidak salah.

Shujal
sumber
4

Pertanyaan pemrograman tanpa jawaban yang melibatkan rekursi? Tak terbayangkan!

Ada cukup jawaban "tepat 3 dari 4 tanda", tetapi inilah versi umum (Java) untuk "persisnya keluar dari tanda" (jika rekursi tidak benar-benar layak) hanya karena Anda dapat:

public static boolean containsTrues(boolean[] someBooleans,
    int anIndex, int truesExpected, int truesFoundSoFar) {
  if (anIndex >= someBooleans.length) {
    return truesExpected == truesFoundSoFar; // reached end
  }
  int falsesExpected = someBooleans.length - truesExpected;
  boolean currentBoolean = someBooleans[anIndex];
  int truesFound = truesFoundSoFar + (currentBoolean ? 1 : 0);
  if (truesFound > truesExpected) {
    return false;
  }
  if (anIndex - truesFound > falsesExpected) {
    return false; // too many falses
  }
  return containsTrues(someBooleans, anIndex + 1, truesExpected,
      truesFound);
}

Ini bisa disebut dengan sesuatu seperti:

 boolean[] booleans = { true, false, true, true, false, true, true, false };
 containsTrues(booleans, 0, 5, 0);

yang harus dikembalikan true(karena 5 dari 8 nilai benar, seperti yang diharapkan). Tidak cukup senang dengan kata-kata "trues" dan "falses", tetapi tidak dapat memikirkan nama yang lebih baik sekarang .... Perhatikan bahwa rekursi berhenti ketika terlalu banyak true atau terlalu banyak falsenilai telah ditemukan.

Amos M. Carpenter
sumber
@ FélixSaparelli: Tidak yakin "kebenaran" berlaku di sini ... sepertinya Anda senang hanya dengan satu true. Mungkin kira-kira seperti itu containsNumberOfTrueValues(). Sebagai samping: Smalltalk ini penamaan akan jauh lebih cocok untuk ini, meskipun: doesArray: someBooleans startingAt: anIndex containNumberOfTrueValues: anExpectedNumber foundSofar: aNumberFoundSoFar. Mungkin terlalu lama untuk selera beberapa devs Jawa, tetapi Smalltalkers tidak pernah takut penamaan yang tepat ;-)
Amos M. Carpenter
Itu sebagian besar lucu. Dan containsTruthberarti "mengandung sejumlah kebenaran yang tidak diungkapkan", secara literal, jadi saya yakin itu tidak apa-apa.
Félix Saparelli
3

Karena keterbacaan adalah masalah besar, Anda bisa menggunakan panggilan fungsi deskriptif (membungkus salah satu implementasi yang disarankan). Jika perhitungan ini perlu dilakukan di banyak tempat, pemanggilan fungsi adalah cara terbaik untuk mencapai penggunaan kembali, dan memperjelas apa yang Anda lakukan.

bool exactly_three_true_from(bool cond1, bool cond2, bool cond3, bool cond4)
{
    //...
}
Graham Griffiths
sumber
3

Di PHP, buatlah lebih dinamis (kalau-kalau Anda mengubah sejumlah kondisi, dll.):

$min = 6;
$total = 10;

// create our boolean array values
$arr = array_map(function($a){return mt_rand(0,1)>0;},range(1,$total));

// the 'check'
$arrbools = array_map(function($a){return (int)$a;},$arr);
$conditionMet = array_sum($arrbools)>=$min;

echo $conditionMet ? "Passed" : "Failed";
Bill Ortell
sumber
2
(((a AND b) OR (x AND y)) AND ((a XOR b) OR (x XOR y)))

Sementara saya bisa menunjukkan bahwa ini adalah solusi yang baik, jawaban Sam Hocevar mudah untuk ditulis dan dipahami kemudian. Dalam buku saya itu membuatnya lebih baik.

Jack Stout
sumber
1

Berikut adalah beberapa kode c # yang baru saja saya tulis karena Anda telah menginspirasi saya:

Dibutuhkan sejumlah argumen dan akan memberi tahu Anda jika tidak ada yang benar.

    static bool boolTester(int n, params bool[] values)
    {
        int sum = 0;           

        for (int i = 0; i < values.Length; i++)
        {
            if (values[i] == true)
            {
                sum += 1;
            }                
        }
        if( sum == n)
        {
            return true;
        }            
        return false;                
    }

dan Anda menyebutnya seperti itu:

        bool a = true;
        bool b = true;
        bool c = true;
        bool d = false;            

        bool test = false;
        test = boolTester(3, a, b, c, d);

Jadi sekarang Anda dapat menguji 7/9 atau 15/100 seperti yang Anda mau.

JPK
sumber