Dari bahasa alami hingga ekspresi C ++

9

Tugas:

Terjemahkan ekspresi bahasa alami berikut ke ekspresi C ++. Asumsikan bahwa semua variabel adalah angka non-negatif atau boolean (bernilai benar atau salah).

Bahasa alami:

Baik a dan b keduanya salah atau c benar, tetapi tidak keduanya.

Solusi saya:

(a==0 && b==0)xor(c==1)

Solusi profesor:

(!a && !b) != c

Pertanyaan:

  1. Saya pikir saya sedikit memahami tanda kurung pertama, dengan mengatakan "tidak-a" dan "tidak-b" Saya pikir bahwa a dan b harus salah, asalkan ab diasumsikan tidak nol pada awalnya. Baik?

  2. Tetapi bagaimana dengan bagian yang mengatakan "tidak sama dengan c"?

  3. Saya tidak mengerti solusi Profesor, adakah yang bisa memecahnya untuk saya?

Terima kasih atas bantuannya!

limonade
sumber
secara umum saya akan berhati-hati dengan menerjemahkan ekspresi bahasa boolean ke kode. Kesalahan umum adalah menerjemahkan "A sama dengan B atau C" menjadi a == b or cbukan a == b or a ==c. Masalahnya adalah bahwa bahasa yang diucapkan tidak tepat dan sebenarnya kedua interpretasi tersebut dapat valid
idclev 463035818

Jawaban:

5

Saya akan menganggap itu a, bdan csekarang bool.

Mari kita menggambar beberapa tabel kebenaran:

| a | !a | a==1 | a==0 |
| 0 |  1 |   0  |   1  |
| 1 |  0 |   1  |   0  |

Seperti yang Anda lihat, adan a==1setara, dan !adan a==0juga setara, jadi kami dapat menulis ulang (a==0 && b==0)xor(c==1)sebagai (!a && !b) xor c.

Sekarang beberapa tabel kebenaran:

| a | b | a xor b | a != b |
| 0 | 0 |    0    |    0   |
| 0 | 1 |    1    |    1   |
| 1 | 0 |    1    |    1   |
| 1 | 1 |    0    |    0   |

Jadi a!=bsetara dengan a xor b, sehingga kita dapat menulis ulang (!a && !b) xor cuntuk (!a && !b)!=c. Seperti yang Anda lihat, solusi Anda sepenuhnya setara, hanya ditulis dengan 'tanda' yang berbeda.


UPD : Lupa menyebutkan. Ada alasan mengapa solusi profesor terlihat persis seperti itu.

Solusi profesor lebih idiomatis. Meskipun solusi Anda secara teknis benar, itu bukan kode C ++ idiomatik.

Masalah kecil pertama adalah penggunaan tipe. Solusi Anda bergantung pada konversi antara intdan boolketika Anda membandingkan nilai boolean dengan angka atau penggunaan xor, yang juga merupakan operator 'bit-wise eksklusif atau' yang bekerja pada ints juga. Dalam C ++ modern jauh lebih dihargai untuk menggunakan nilai-nilai dari jenis yang benar dan tidak bergantung pada konversi seperti itu karena mereka kadang-kadang tidak begitu jelas dan sulit untuk dipikirkan. Untuk boolnilai-nilai tersebut truedan falsebukannya masing 1- 0masing. Juga !=lebih tepat daripada xorkarena sementara secara teknis booldisimpan sebagai angka, tetapi secara semantik Anda tidak memiliki angka, hanya nilai logis.

Masalah kedua adalah tentang idiomasi juga. Ini terletak di sini: a == 0. Tidak dianggap praktik yang baik untuk membandingkan ekspresi boolean dengan konstanta boolean. Seperti yang sudah Anda ketahui, a == truesepenuhnya setara dengan adil a, dan a == falseadil !aatau not a(saya lebih suka yang terakhir). Untuk memahami alasan mengapa pembandingan itu tidak baik, bandingkan saja dua cuplikan kode dan putuskan, yang lebih jelas:

if (str.empty() == false) { ... }

vs.

if (not str.empty()) { ... }
Yuri Kovalenko
sumber
1
Meskipun secara teknis benar, jawaban ini benar-benar menghindari berbicara tentang tipe dan C ++ idiomatik, yang mungkin merupakan inti dari latihan ini.
Konrad Rudolph
@KonradRudolph, oh, ya, saya benar-benar lupa menyebutkan itu. Mungkin saya akan mengedit jawaban saya, terima kasih
Yuri Kovalenko
3

Pikirkan booleans, bukan bit

Singkatnya, solusi profesor Anda lebih baik (tetapi masih salah, secara tegas, lihat lebih jauh ke bawah) karena menggunakan operator boolean, bukan operator bitwise dan memperlakukan boolean sebagai bilangan bulat. Ungkapan c==1untuk mewakili "c benar" salah karena jika c dapat berupa angka (sesuai dengan penugasan yang dinyatakan) maka nilai bukan-nol dari c dianggap dianggap mewakili true.

Lihat pertanyaan ini tentang mengapa lebih baik tidak membandingkan boolean dengan 0 atau 1, bahkan ketika itu aman untuk dilakukan.

Satu alasan yang sangat bagus untuk tidak digunakan xoradalah karena ini adalah operasi atau bit-wise . Ini terjadi pada contoh Anda karena sisi kiri dan kanan adalah ekspresi boolean yang dikonversi menjadi 1 atau 0 (lihat lagi 1 ).

Boolean eksklusif-atau sebenarnya !=.

Memecah ekspresi

Untuk memahami solusi profesor Anda dengan lebih baik, lebih mudah untuk mengganti operator boolean dengan padanan "alternatif token" mereka, yang mengubahnya menjadi lebih baik dapat dirubah (imho) dan kode C ++ yang sepenuhnya setara: Menggunakan 'bukan' untuk '!' dan 'dan' untuk '&&' Anda dapatkan

    (not a and not b) != c

Sayangnya, tidak ada exclusive_oroperator logis selain not_eq, yang tidak membantu dalam kasus ini.

Jika kita memecah ekspresi bahasa alami:

Baik a dan b keduanya salah atau c benar, tetapi tidak keduanya.

pertama menjadi kalimat tentang proposisi boolean A dan B:

Baik A atau B, tetapi tidak keduanya.

ini diterjemahkan menjadi A != B(hanya untuk boolean, bukan untuk tipe A dan B).

Kemudian proposisi A adalah

a dan b keduanya salah

yang dapat dinyatakan sebagai

a salah dan b salah

yang diterjemahkan menjadi (not a and not b), dan akhirnya

c benar

Yang diterjemahkan menjadi c. Menggabungkan mereka, Anda dapatkan lagi (not a and not b) != c.

Untuk penjelasan lebih lanjut bagaimana ungkapan ini kemudian bekerja, saya tunduk pada tabel kebenaran yang telah diberikan orang lain dalam jawaban mereka.

Anda berdua salah

Dan jika saya dapat melakukan nitpick: Tugas asli menyatakan bahwa a, b dan c dapat berupa angka-angka yang tidak negatif, tetapi tidak secara jelas menyatakan bahwa jika itu adalah angka, angka-angka tersebut harus dibatasi dengan nilai 0 dan 1. Jika ada angka yang bukan 0 mewakili true, seperti kebiasaan, maka kode berikut akan menghasilkan jawaban yang mengejutkan :

    auto c = 2; // "true" in some way
    auto a = 0; // "false"
    auto b = 0; // "false"

    std::cout << ((!a && !b) != c);

// this will output: 1 (!)
// fix by making sure that != compares booleans:

    std::cout << ((!a && !b) != (bool)c);
dhavenith
sumber
Yah mudah-mudahan a, bdan cdinyatakan sebagai bool, dalam hal c == 1ini kode yang benar , meskipun mengerikan. Bagaimanapun, ini adalah jawaban yang akan saya tulis: Kode OP mungkin setara dengan profesor, tapi itu buruk C ++.
Konrad Rudolph
1
@KonradRudolph Dari teks tugas OP: variables are non-negative numbers or boolean. Jadi +1 ke @dhavenith dari saya karena menangkap detail yang kebanyakan orang lain lewatkan (termasuk saya, awalnya).
Frodyne
Hebat, Isee. Terima kasih! Tetapi bisakah Anda kemudian menjelaskan kepada saya solusi Profesor saya karena saya tidak memahaminya.
limonade
Saya telah menambahkan ejaan alternatif untuk solusi profesor Anda. Ini akan membantu memperjelas ekspresi. Untuk penjelasan lebih rinci, saya pikir tabel kebenaran dalam jawaban oleh @ YuriKovalenko adalah cara terbaik untuk mendekati ekspresi.
dhavenith
2

Saya akan mencoba menjelaskan dengan beberapa kata lagi: Angka dapat secara implisit dikonversi menjadi nilai boolean:

Nilai nol (untuk enumerasi integral, floating-point, dan unscoped) dan null pointer dan nilai null-to-member null menjadi salah. Semua nilai lain menjadi benar.

Sumber di cppreference

Ini mengarah pada kesimpulan berikut:

  • a == 0sama dengan !a, karena adikonversi ke boolean dan kemudian dibalik, yang sama dengan !(a != 0). Hal yang sama berlaku untuk b.

  • c==1hanya akan menjadi benar ketika c sama dengan 1. Menggunakan konversi (bool)cakan menghasilkan truebila c != 0tidak hanya jika c == 1. Jadi itu bisa berhasil, karena orang biasanya menggunakan nilai 1 untuk mewakili true, tetapi tidak garantued.

  • a != bsama dengan a xor bkapan adan bekspresi boolean. Itu benar, ketika satu nilai atau yang lain benar, tetapi tidak keduanya. Dalam hal ini sisi kiri (a==0 && b==0)adalah boolean, sehingga sisi kanan cdikonversi menjadi boolean juga, dengan demikian, kedua belah pihak ditafsirkan sebagai ekspresi boolean, dengan demikian !=sama seperti xordalam kasus ini.

Anda dapat memeriksa sendiri semua ini dengan tabel kebenaran yang disediakan oleh jawaban lain.

Churill
sumber
2

Seperti yang bisa kita lihat dari tabel kebenaran:

  • !( not) dan ==0berikan hasil yang sama.
  • !=dan xormemberikan hasil yang sama.
  • c==1 sama dengan adil c

Jadi satu di bawah yang lain, menunjukkan mengapa 2 ekspresi ini memberikan hasil yang sama:

(a==0 && b==0) xor (c==1)
(!a   && !b)   !=   c

Tabel kebenaran:

Tidak

    |   | ! |
    | 0 | 1 |
    | 1 | 0 |

== 0

    |   |==0|
    | 0 | 1 |
    | 1 | 0 |

== 1

    |   |==1|
    | 0 | 0 |
    | 1 | 1 |

Dan

   | a | b | && |
   | 0 | 0 |  0 |
   | 0 | 1 |  0 |
   | 1 | 0 |  0 |
   | 1 | 1 |  1 |

Tidak sama

   | a | b | != |
   | 0 | 0 |  0 |
   | 0 | 1 |  1 |
   | 1 | 0 |  1 |
   | 1 | 1 |  0 |

XOR

   | a | b |xor|
   | 0 | 0 | 0 |
   | 0 | 1 | 1 |
   | 1 | 0 | 1 |
   | 1 | 1 | 0 |
Robert Andrzantai
sumber