2015-09-10 2 views
28

Я начинаю, и я пытаюсь запустить программу, которая печатает все числа от 1 до N (ввод пользователя), за исключением тех, которые делятся на 3 и 7 одновременно. Однако мой код делает то, что он печатает числа от 1 до N, за исключением тех, которые делятся на 3 или 7. Я некоторое время изучал его, и я не знаю, почему он это делает. Пожалуйста, объясните мне, где я ошибаюсь.&& оператор ведет себя как || operator

static void Main(string[] args) 
{ 
    int n = 0; 
    int a = 0; 
    n = Convert.ToInt32(Console.ReadLine()); 
    while (a <= n) 
    { 
     a++; 
     if (a % 3 != 0 && a % 7 != 0) 
     { 
      Console.WriteLine(a); 
     } 
    } 
    Console.ReadKey(); 
} 

Когда я изменить знаки, если заявление на == оператор && работает правильно, но если знак != это просто действует как || оператора, так что меня смущает еще больше. Проблема, скорее всего, в состоянии, но я не вижу, что с ней не так.

+32

Как примечание стороны, число делится на обоих 3 и 7, если, и только если, он делится на 21. – ach

+2

'! (a% 3 == 0 && a% 7 == 0)' – imallett

+1

@ Андрея Черняховского: лучшее обобщение - число делится на оба * a * и * b *, если оно делится на * LCM a и b *. – displayName

ответ

95

«За исключением чисел, которые делятся на 3 и 7, в то же время» может быть разбита следующим образом:

"divisible by 3 and 7 at the same time" может быть выражена как:

"(divisible by 3 and divisible by 7)"

"Except" может быть выражен как "Not".

Таким образом, вы получите:

Not (divisible by 3 and divisible by 7)

"делится на 3" является (a % 3) == 0

"делится на 7" является (a % 7) == 0

Отдает:

Not ((a % 3) == 0 and (a % 7) == 0)

В C# Not становится ! и and становится &&, так что вы можете написать все это в C#, как:

if (!((a % 3) == 0 && (a % 7) == 0))


Сравнить с вашей неправилен:

if (a % 3 != 0 && a % 7 != 0)

Последняя неверно, поскольку это означает:

if (the number is not divisible by 3) and (the number is not divisible by 7).

е. Это означает "Print the number if it is neither divisible by 3 nor divisible by 7", что означает "don't print the number if it's divisible by 3 or 7".

Чтобы понять, почему, рассмотрим сначала номер 6:

6 is not divisible by 3? = false (because 6 *is* divisible by 3) 
6 is not divisible by 7? = true (because 6 is *not* divisible by 7) 

Так что это разрешается в if false and true, который, конечно же, false.

Этот результат также применим к любому другому числу, делящемуся на 3, поэтому числа, делящиеся на 3, не будут напечатаны.

Теперь рассмотрим число 14:

14 is not divisible by 3? = true (because 14 is *not* divisible by 3) 
14 is not divisible by 7? = false (because 14 *is* divisible by 7) 

Так что это разрешается в if true and false, который, конечно же, false.

Этот результат также применим к любому другому числу, делящемуся на 7, поэтому числа, делящиеся на 7, будут напечатаны.

Надеюсь, вы сразу поймете, почему это неправильно.Если нет, то рассмотреть этот эквивалентный пример:


Предположим, что у нас есть четыре человека, Том плотник, Дик Карпентер, Гарри мясник и Том Мясник.

Этот вопрос эквивалентен тому, вы просите:

Name every person who is (not called Tom and is not a Butcher) 

И вы должны быть в состоянии видеть, что это то же самое, спрашивая:

Name every person except (anyone called Tom or anyone who is a Butcher) 

В обоих случаях ответ это Дик Плотник.

Вопрос, который вы должны задать:

Name every person except (anyone called Tom who is also a butcher) 

На что ответ Том Карпентер, Дик Карпентер и Гарри Мясник.


Сноска: De Morgan's laws

Второй закон гласит:

"not (A or B)" is the same as "(not A) and (not B)" 

Это эквивалент моего примера выше, где:

Name every person except (anyone called Tom or anyone who is a Butcher) 

является эквивалентом :

Name every person who is (not called Tom and is not a Butcher) 

где А и В anyone called Tom является anyone who is a butcher и not записывается как except.

+0

Отличный ответ. Однако, теоретически, не следует «если (a% 3! = 0 && a% 7! = 0)» также верно? Моим логичным не является только 2 символа «! =» Вместо одного «!». поэтому я считаю, что это довольно запутанно. – Ornstein

+0

@Ornstein Я добавил дополнительную информацию, чтобы объяснить, почему это неправильно. –

+0

Большое спасибо, я думаю, что я в значительной степени понимаю его. Спасибо, что потратили время на помощь! – Ornstein

73

Вы должны прочитать De Morgan's laws

"не (A и B)" такой же, как "(не) или (не B)"

также

«нет (A или B) "совпадает с" (не A) и (а не B) ".

a % 3 != 0 && a % 7 != 0 верно, когда a не делится на 3 (a % 3 != 0) и не делится на 7 (a % 7 != 0). Таким образом, все a s, которые делятся на или (3,6,7,9,12,14,...) делает все выражение ложным. Вы можете перефразировать это как !(a % 3 == 0 || a % 7 == 0)

+0

Я хочу, чтобы условие было истинным, когда a не делится на 3 и 7, но оно все еще ведет себя так, как если бы оно было 3 или 7. Я заменил условие «if (! (A% 3 == 0 && a% 7 == 0)) «и это сработало, но я все еще не совсем уверен, почему мое начальное условие не делало того же. – Ornstein

+0

@Ornstein Попробуйте прочитать свое начальное состояние вслух; вы должны получить что-то вроде: напечатать a, если a не делит 3, а также не делит 7. Для того, чтобы быть напечатанными, обе части соединения должны быть истинными, поэтому случаи, когда a не печатаются, случаи, когда хотя бы одна из частей ложна. Это делит 3 или делит 7. Это то, что законы Де Моргана говорят вам. – Taemyr

+1

Существует простое решение, чтобы избежать таких неловких ситуаций, используйте больше скобок, чем это строго необходимо. – Caridorc

9

Должно быть:

if (!(a % 3 == 0 && a % 7 == 0)) 
{ 
    Console.WriteLine(a); 
} 

Это означает, что именно: все числа тех, которые делятся на 3 и 7, в то же время, за исключением.

Вы также могли бы перефразировать как:

if (a % 3 != 0 || a % 7 != 0) 
{ 
    Console.WriteLine(a); 
} 
+0

Спасибо, ваше решение сработало. Второй фрагмент кода кажется мне немного странным, но это имеет смысл. Можете ли вы объяснить мне более подробно, почему ваше первое заявление работает, но мое, если возможно, не работает? – Ornstein

+0

@Ornstein Используя слова как @MatthewWatson, ваше утверждение говорило: «Если а не делится на 3 И а не делится на 7», но ответ @ user2622016 говорит «если это неверно, что он делится на BOTH 3 и 7', , Число, например ** 6 **, не пройдет проверку, но будет проходить проверка @ user2622016. Если вы распространяете 'not' в начале кода @ user2622016, вы получаете вторую часть кода. Это почти идентично коду, который вы изначально разместили, но при распространении 'not' нам нужно изменить '&&' на '||' и изменить '||' на '&&'. –

0

& & ведет себя по-разному, чтобы ||

Чтобы понять разницу, это может помочь сделать некоторые тесты с более простыми выражениями:

if (true && false) 
if (true || false) 

Итак, ваша проблема с пониманием других операторов в коде (= и%!).

Это часто помогает разделить условия на меньшие выражения, с объяснениями:

bool divisbleBy3 = (a % 3 == 0); 
bool divisbleBy7 = (a % 7 == 0); 

if (divisbleBy3 && divisibleBy7) 
{ 
    // do not print 
} 
else 
{ 
    // print 
} 
+1

Да, результат отличается. В этом весь смысл иметь два разных оператора, если бы результат был тем же самым из операторов, был бы лишним. Какова ваша позиция? – SJuan76

+0

Ну, дело в том, чтобы ответить на вопрос. Посмотрите на название ... :-) – buffjape

+0

Тогда вы ответили на заголовок, но не на вопрос – Liam

9

Что ты сказал:

if not (divisible by 3 and divisible by 7) then print 

Что Вы писали:

if not divisible by 3 and not divisible by 7 then print 

Не то же самое. Аристотель думал об этом первым, Огастес де Морган написал законы 158 лет назад, применять не оператор к операндам и инвертировать логическую операцию:

if not divisible by 3 or not divisible by 7 then print 

Который производит:

if (a % 3 != 0 || a % 7 != 0) 

Или просто написать его как вы это сказали:

if (!(a % 3 == 0 && a % 7 == 0)) 
+0

Первая часть имеет большой смысл. После упоминания логического оператора OR я просто теряюсь. Как оператор OR мог охватить ситуацию, когда два значения должны отвечать условию в одно и то же время? Я понимаю, что вы говорите правильно, но я не понимаю, почему. Я знаю, что законы Де Моргана содержат много информации о инвертирующих операторах, но оператор OR, удовлетворяющий синхронному состоянию, звучит совершенно запутанным и невозможным для меня. Не могли бы вы дать мне простое объяснение, если вы не возражаете? – Ornstein

+0

Не уверен, что я могу понять ваше зависание, я делал это слишком долго. Я предполагаю, что вас смутила замена == by! =. Может быть, легче получить, когда вы это сделаете с переменными типа * bool *.Подобно bool divisiblyBy3 = a% 3 == 0; то же для divisiblyBy7, а затем записать оператор if(). Помимо этого, мистер ДеМорган - ваш друг, всегда держите его под рукой. –

+0

Некоторым другим ответам удалось заполнить пробелы, и я понимаю это сейчас. Просто использование оператора OR позволяет решить, делится ли он на 3 и 7, радикально отличающийся от использования оператора И. Кроме того, возможно, я должен был перечитать задачу сам еще пару раз, потому что теперь, когда я это сделал, мне удалось легче понять концепцию. В любом случае, ваш ответ в сочетании с двумя другими помог мне понять эту проблему. Большое вам спасибо за вашу помощь и ваше время! – Ornstein

4

a % b != 0 означает «не делится на Ь».

Если что-то не делится на 3 и не делится на 7, оно делится на ни. Таким образом, если оно кратно 3 или, кратное 7, ваше утверждение будет ложным.

Это часто помогает думать о логике с точки зрения реальных вещей:
(имейте в виду, что true and false == false и true or false == true)

Океан синий (а делится на 3).
Океан не желтый (а не делится на 7).

Что у вас есть:
Океан не голубой и океан не желтый - это ложь (вы хотите, чтобы это было правдой).

Что вы хотите:
океан не является (синий и желтый) - это правда (океан только синий, а не как синий и желтый).
Океан не голубой или океан не желтый - это правда (океан не желтый).

Эквивалент 2 последних заявлений будет:

!(a % 3 == 0 && a % 7 == 0) 
(a % 3 != 0 || a % 7 != 0) 

И вы можете конвертировать один в другой с помощью De Morgan's laws.

1

Если вы не знаете, как реализовать алгоритм, попробуйте разбить его, очевидно, правильные функции, каждый реализует части алгоритма.

Вы хотите «напечатать все числа от 1 до N (ввод пользователя), за исключением тех, которые делятся на 3 и 7 одновременно». Старые таймеры могут быстро выплевывать правильную и эффективную реализацию с использованием логических операторов. Как новичок, вы можете обнаружить, что это помогает разбить его на кусочки.

// write out the highest level problem to solve, using functions as 
// placeholders for part of the algorithm you don't immediately know 
// how to solve 
for ($x = 1; $x <= $N; $x++) { 
    if (is_not_divisible_by_3_and_7($x)) { 
     print "$x\n"; 
    } 
} 

// then think about the function placeholders, writing them out using 
// (again) function placeholders for things you don't immediately know 
// how to do 
function is_not_divisible_by_3_and_7($number) { 
    if (is_divisible_by_3_and_7($number)) { 
     return false; 
    } else { 
     return true; 
    } 
} 

// keep repeating this... 
function is_divisible_by_3_and_7($number) { 
    if (is_divisible_by_3($number) && is_divisible_by_7($number)) { 
     return true; 
    } else { 
     return false; 
    } 
} 

// until you have the simplest possible functions 
function is_divisible_by_3($number) { 
    if ($number % 3 === 0) { 
     return true; 
    } else { 
     return false; 
    } 
} 

function is_divisible_by_7($number) { 
    if ($number % 7 === 0) { 
     return true; 
    } else { 
     return false; 
    } 
} 

Это проще понять, потому что каждая функция выполняет одну функцию, а имя функции описывает именно эту вещь. Это также удовлетворяет первому правилу программирования: правильный код на первом месте.

Вы можете начать думать сделать код лучше, где лучше может означать:

  • меньше строк кода
  • меньше расчетов
  • еще комментариев

Взятие этот подход с приведенным выше кодом, очевидным улучшением является замена is_divisible_by_3 и is_divisible_by_7 с общим f соборование:

function is_divisible_by_n($number, $divisor) { 
    if ($number % $divisor === 0) { 
     return true; 
    } else { 
     return false; 
    } 
} 

Вы можете заменить все большие, громоздкие if x return true else return false с тройным оператором, который получает Вас:

function is_divisible_by_n($number, $divisor) { 
    return ($number % $divisor === 0) ? true : false; 
} 

function is_divisible_by_3_and_7($number) { 
    return (is_divisible_by_n($number, 3) && is_divisible_by_n($number, 7)) ? true : false; 
} 

function is_not_divisible_by_3_and_7($number) { 
    return (is_divisible_by_3_and_7($number)) ? false : true; 
} 

Теперь, обратите внимание, что is_not_divisible_by_3_and_7 выглядит точно так же, как is_divisible_by_3_and_7, за исключением того, что отдача коммутацией каналов, так что вы можете свернуть те в один метод:

function is_not_divisible_by_3_and_7($number) { 
    // look how it changed here ----------------------------------------------VVVVV - VVVV 
    return (is_divisible_by_n($number, 3) && is_divisible_by_n($number, 7)) ? false : true; 
} 

Теперь, вместо того, чтобы использовать тройные операторы, которые можно Leverag е тот факт, что сравнение себя возвращает значение:

function is_divisible_by_n($number, $divisor) { 
    // this expression returns a "truthy" value: true or false 
    //  vvvvvvvvvvvvvvvvvvvvvvvvvv 
    return ($number % $divisor === 0); 
} 

function is_not_divisible_by_3_and_7($number) { 
    // also returns a truthy value, but inverted because of the ! 
    // vvv 
    return ! (is_divisible_by_n($number, 3) && is_divisible_by_n($number, 7)); 
} 

Наконец, вы можете просто механически заменить вызовы функций с их эквивалентными логическими операциями:

for ($x = 1; $x <= $N; $x++) { 
    // all I did below was copy from the function, replace variable names 
    // v vvvvvvvvvvvvvv vvvvvvvvvvvvvv 
    if (! (($x % 3 === 0) && ($x % 7 === 0))) { 
     print "$x\n"; 
    } 
} 

В качестве бонусных очков, то вы можете применить правило де Моргана , чтобы распространять не через выражение:

for ($x = 1; $x <= $N; $x++) { 
    if ($x % 3 !== 0 || $x % 7 !== 0) { 
     print "$x\n"; 
    } 
} 

Кроме того, вы можете заметить, что два со-простые числа имеют общие факторы, если и только если они га ве общий множитель N раз M, так:

for ($x = 1; $x <= $N; $x++) { 
    if ($x % (3*7) !== 0) { 
     print "$x\n"; 
    } 
} 

Вы можете принять это дальше, используя возможности своего языка, чтобы уплотнить выражение больше:

array_walk(
    range(1, $N), 
    function ($x) { 
     if ($x % 21 !== 0) print "$x\n"; 
    } 
); 

И так далее. Дело в том, что вы начинаете с правильного написания кода, затем вы делаете это лучше. Иногда создание правильного кода означает долгое и долгое мышление. Иногда это просто означает писать его очень маленькими, очень ясными шагами.

5

Глядя Таблица истинности вашего условного оператора в вы можете увидеть, что если

X(NOT multiple of 3) Y(NOT multiple of 7) X && Y 
     true     true   'a' printed as it is not a multiple of either 
     true     false   'a' not printed, it is multiple of 7 
     false     true   'a' not printed, it is multiple of 3 
     false     false   'a' not printed, it is multiple of both 

Вот почему все кратные 3 или 7 или 21, не печатаются.


Что вы хотите: Числа, которые

  • не(кратно 3 и 7).И это
  • ! (А% 3 == 0 & & A% 7 == 0) или даже еще более упрощен до
  • ! (А% 21 == 0) или даже
  • (!% 21 = 0)
+1

Я думаю, что ** это ** действительно является основным ответом на вопрос. Оператор '&&' выполняет _exactly_ то, что он говорит, что он будет делать; просто следуйте за оценкой выражения шаг за шагом. –

9

Все, что вам действительно нужно:

if ((a%21) != 0) Console.WriteLine(a); 

Пояснение: Числа, которые делятся на обоих и б, по существу, число делится на LCM а и б.Так как 3 и 7 являются простым числом, вы в основном ищете числа, которые не делятся на 3 * 7.

+1

Потребовалось секунду, чтобы понять, что у вас есть точка, которую никто другой не сделал. – kleineg

+1

@kleineg было сделано в комментарии. Но да, это, безусловно, лучший способ решить эту проблему. Все те сообщения, которые четко и подробно объясняют, как сделать плохо разработанную программу ... печально. – Yakk

+0

@Yakk Я согласен. Имеет смысл, что люди отвечали на вопрос по номиналу (хотя многие ответы излишни), потому что он способствует пониманию законов Де Моргана, что было бы полезно при отрицании условного утверждения. Но верно и то, что в этом случае существует ... более элегантное решение. Thumbs и голосуют за это. – kleineg

-1

& & и || разные.

Она гласит: , если (истинная & & ложь) = FALSE, если (истина || ложь) = TRUE

Смежные вопросы