Упрощение логики операторов - PullRequest
2 голосов
/ 15 января 2010

Я разделил тест, чтобы определить, перекрываются ли два элемента расписания из-за его нечитаемости.

Есть ли какое-либо приложение, которое поможет упростить логическое утверждение?

Пример: (изначально ошибочный пример, но приводятся причины, по которым я его запрашиваю)

if (x < y && y < z && x < z)  

может быть уменьшено до

if (x < y && y < z)

Мой код:

return (shift.Start <= shift2.Start && shift.End >= shift2.End) || (shift2.Start <= shift.Start && shift2.End >= shift.Start)

Я бы хотел сделать это проще, и я верю, что это возможно, просто не знаю, как.

Видя, что это действительно не зависит от языка, было бы неплохо даже конвертировать в другой скрипт, чтобы найти возможности, не нужно, чтобы он был в C #, например.

Ответы [ 11 ]

8 голосов
/ 16 января 2010

Убейте дублирующую логику, и вы убьете двух зайцев одним выстрелом. Вы получите СУХОЙ, и вы получите имя функции (комментарий богатого человека):

class Shift:
  def encompasses(other_shift)
    self.start <= other_shift.start && self.end >= other_shift.end

...

return shift1.encompasses(shift2) || shift2.encompasses(shift1)
6 голосов
/ 15 января 2010

Будьте очень, очень осторожны с такого рода изменениями. Они могут показаться простыми с первого взгляда, и логическая логика (и законы Деморгана) не слишком сложны для понимания, но при рассмотрении отдельных случаев часто есть потенциальные ошибки:

Например: if (x

Это не правильно, если (x < z), y может быть больше, чем z. Это состояние не пройдет ваши первоначальные испытания.

4 голосов
/ 15 января 2010

Хотя x < y && y < z подразумевает x < z (<является транзитивным), обратное неверно, поэтому выражения не эквивалентны. Действительно, если <code>y было определено, скажем, как Integer y = null, то первое может даже вызвать NPE в Java или НЕИЗВЕСТНО в SQL.

3 голосов
/ 16 января 2010

Есть ли какое-либо приложение, помогающее упростить логическое утверждение?

Я не видел, чтобы кто-то обращался к этой части вопроса, поэтому я сделаю удар и посмотрю, что происходит.

Существуют методы для работы с булевой логикой. Еще в студенческие годы (BSEE) мы использовали карты Карно . По сути, вы можете взять очень сложную таблицу произвольных истин и определить правильное и оптимизированное логическое выражение. Мы использовали это для уменьшения количества логических элементов в схеме, что аналогично упрощению сложного оператора if.

Плюсы:

  • Вы можете относительно легко реализовать / оптимизировать очень сложную и произвольную таблицу истинности.

Минусы:

  • Получающаяся логика обычно мало напоминала намерения таблицы истинности. Как и предполагали другие, это «нечитабельно».
  • Изменение одной ячейки таблицы истинности часто приводит к совершенно другому выражению. Простая настройка становится перезаписью, поэтому она не поддерживается.
  • Неоптимизированная логика намного дешевле, чем раньше, в то время как затраты на проектирование такие же.

В конечном счете, наиболее важной вещью является правильность таблицы истинности / логического выражения. Ошибка означает, что ваша программа не будет работать правильно. Никакое приложение или методика проектирования не помогут, если вы не правильно понимаете определение логики, которая должна быть реализована.

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

2 голосов
/ 15 января 2010

Когда речь идет о сложных логических утверждениях, обычно лучше отформатировать код в удобочитаемой форме, чем пытаться провести некоторую преждевременную оптимизацию (корень зла и т. Д.)

Например:

return (shift.Start <= shift2.Start && shift.End >= shift2.End) || (shift2.Start <= shift.StartTime && shift2.End >= shift.Start)

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

bool bRetVal = false;
bRetVal = (    (   (shift.Start <= shift2.Start)
                && (shift.End >= shift2.End))
            || (   (shift2.Start <= shift.StartTime)
                && (shift2.End >= shift.Start)))
return bRetVal;

В большинстве мест поддерживается стандарт кодирования, который определяет что-то подобное выше для больших логических блоков. Я бы предпочел сохранить несколько дополнительных строк кода, которые можно прочитать и понять, чем однострочное чудовище.

2 голосов
/ 15 января 2010

Вы должны быть очень осторожны при выполнении этого ... пример, который вы привели, например, просто не соответствует действительности ... если x = 1, y = 2 и z = 2, то x

1 голос
/ 15 января 2010

Если предположить, что Start и StartTime фактически должны быть одним и тем же полем, ваше условие сводится к

(a <= b && c >= d) || (b <= a && d >= c)

Мы можем превратить это в

(a <= b && d <= c) || (b <= a && c <= d)

, но это по-прежнему непохоже, это сильно упрощает.

1 голос
/ 15 января 2010

Иногда вы можете заключить такие выражения, как

shift.Start <= shift2.Start && shift.End> = shift2.End

В булеву функцию, чтобы сделать ее более читабельной, например:

Функция ShiftWithinValidRange (ужасное название здесь, но вы поняли)
{
Return (shift.Start <= shift2.Start && shift.End> = shift2.End);
}

0 голосов
/ 16 января 2010

Я думаю, что ответ Уэйна Конрада правильный, но только для развлекательных целей, вот другой способ сказать это (я думаю):

(long) shift.Start.CompareTo(shift2.Start) * (long) shift.End.CompareTo(shift2.End) <= 0

Это на самом деле быстрее? Я не знаю. Это, конечно, труднее читать.

0 голосов
/ 16 января 2010

У меня нет общего решения для вас, но если я использую синтаксис Lisp, мне это будет выглядеть намного проще:

(and (< x y)
     (< y z)
     (< x z))

Тогда обратите внимание, что первые два пункта:

(and (< x y)
     (< y z))

можно объединить в:

(and (< x y z))

Таким образом, полное выражение теперь выглядит так:

(and (< x y z)
     (< x z))

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

(and (< x y z))

или просто:

(< x y z)

который в C-синтаксисе:

(x < y && y < z)
...