# Is !(p && q) exactly the same as !p || !q?

**URL:** <https://boards.straightdope.com/t/is-p-q-exactly-the-same-as-p-q/804388>\
**Category:** Factual Questions\
**Created:** [December 13, 2017, 1:18pm UTC](https://boards.straightdope.com/t/is-p-q-exactly-the-same-as-p-q/804388 "2017-12-13T13:18:23Z")\
**Posts on this page:** 20\
**Page:** 4

<div class="post-metadata">

**Author:** ![Chronos](https://sea3.discourse-cdn.com/straightdope/user_avatar/boards.straightdope.com/chronos/32/134_2.png) [@Chronos](https://boards.straightdope.com/u/Chronos)\
**Post date:** [December 15, 2017, 1:55am UTC](https://boards.straightdope.com/t/is-p-q-exactly-the-same-as-p-q/804388/61 "2017-12-15T01:55:15Z")

</div>

You want to really blow their minds, show them… Um, what’s the name of that weird two-column construction using case?

---

<div class="post-metadata">

**Author:** ![LSLGuy](https://sea3.discourse-cdn.com/straightdope/user_avatar/boards.straightdope.com/lslguy/32/5813_2.png) [@LSLGuy](https://boards.straightdope.com/u/LSLGuy)\
**Post date:** [December 15, 2017, 3:00am UTC](https://boards.straightdope.com/t/is-p-q-exactly-the-same-as-p-q/804388/62 "2017-12-15T03:00:17Z")

</div>

> [@eschereal](#):
>
> I was led to understand that & and | are arithmetic masking operators that are always fully evaluated, whereas && and || are logical operators that do short-circuit. For instance, 42&7 returns 2 and 42|7 returns 47: you can & two true values and end up with false (e.g., 42&6 = 0). You should probably never use & or | for logical constructions, opting instead for && and ||, unless you know exactly what you are doing.

Which language and processor are you discussing? Rest assured some of what you assert is 100% true in some environments, 100% false in others, and 50/50 true & false in yet another group.

Which is really the big point of the thread: These details matter. Be explicit. Or be buggy. There is no third choice.

---

<div class="post-metadata">

**Author:** ![eschereal](https://sea3.discourse-cdn.com/straightdope/user_avatar/boards.straightdope.com/eschereal/32/18939_2.png) [@eschereal](https://boards.straightdope.com/u/eschereal)\
**Post date:** [December 15, 2017, 3:19am UTC](https://boards.straightdope.com/t/is-p-q-exactly-the-same-as-p-q/804388/63 "2017-12-15T03:19:52Z")

</div>

> [@LSLGuy](#):
>
> Which language and processor are you discussing? Rest assured some of what you assert is 100% true in some environments, 100% false in others, and 50/50 true & false in yet another group.
> 
> Which is really the big point of the thread: These details matter. Be explicit. Or be buggy. There is no third choice.

Well, C, of course, because all other languages are evil: they are not-C.

> [@Chronos](#):
>
> You want to really blow their minds, show them… Um, what’s the name of that weird two-column construction using case?

**switch**

---

<div class="post-metadata">

**Author:** ![Francis\_Vaughan](https://sea3.discourse-cdn.com/straightdope/user_avatar/boards.straightdope.com/francis_vaughan/32/3093_2.png) [@Francis\_Vaughan](https://boards.straightdope.com/u/Francis_Vaughan)\
**Post date:** [December 15, 2017, 4:23am UTC](https://boards.straightdope.com/t/is-p-q-exactly-the-same-as-p-q/804388/64 "2017-12-15T04:23:30Z")

</div>

In C and its derivatives the rule on evaluation was put in as an explicit language feature to short circuit the need for cascading if statements when you needed to guard an expression:

```auto

if ptr != NULL {
    if *ptr == thing {
        some action
    }
}

```

versus

```auto

if prt != NULL && *ptr == thingy {
    some action
}

```

That is really all there is. There is no other deeper reason for having the rule. Not all languages really needed it, many don’t, and some would regard the idea as a hack.

---

<div class="post-metadata">

**Author:** ![Dr.Strangelove](https://sea3.discourse-cdn.com/straightdope/user_avatar/boards.straightdope.com/dr.strangelove/32/6613_2.png) [@Dr.Strangelove](https://boards.straightdope.com/u/Dr.Strangelove)\
**Post date:** [December 15, 2017, 6:54am UTC](https://boards.straightdope.com/t/is-p-q-exactly-the-same-as-p-q/804388/65 "2017-12-15T06:54:01Z")

</div>

> [@eschereal](#):
>
> **switch**

No ordinary switch. **Chronos** is talking about [Duff’s Device](https://en.wikipedia.org/wiki/Duff%27s_device):

```php
register short *to, *from;
register count;
{
    register n = (count + 7) / 8;
    switch (count % 8) {
    case 0: do { *to = *from++;
    case 7: *to = *from++;
    case 6: *to = *from++;
    case 5: *to = *from++;
    case 4: *to = *from++;
    case 3: *to = *from++;
    case 2: *to = *from++;
    case 1: *to = *from++;
            } while (--n > 0);
    }
}

```

---

<div class="post-metadata">

**Author:** ![LSLGuy](https://sea3.discourse-cdn.com/straightdope/user_avatar/boards.straightdope.com/lslguy/32/5813_2.png) [@LSLGuy](https://boards.straightdope.com/u/LSLGuy)\
**Post date:** [December 15, 2017, 1:08pm UTC](https://boards.straightdope.com/t/is-p-q-exactly-the-same-as-p-q/804388/66 "2017-12-15T13:08:55Z")

</div>

With great power comes great (ir)responsibility.

That \*is \*a bug, not a feature. Yes it works. Yes it’s evil. Yes it’s C.

---

<div class="post-metadata">

**Author:** ![Francis\_Vaughan](https://sea3.discourse-cdn.com/straightdope/user_avatar/boards.straightdope.com/francis_vaughan/32/3093_2.png) [@Francis\_Vaughan](https://boards.straightdope.com/u/Francis_Vaughan)\
**Post date:** [December 15, 2017, 3:09pm UTC](https://boards.straightdope.com/t/is-p-q-exactly-the-same-as-p-q/804388/67 "2017-12-15T15:09:53Z")

</div>

Many years ago I invented Duff’s device myself whilst trying to accelerate a copy loop. I though I was pretty clever until I looked into the underlying implications of what actually happens. First up it can break branch prediction, so your pipeline stalls and loops go slower. Secondly, unless you can convince your compiler otherwise (and depending upon the compiler there _may_ be ways) it may decide that since there are essentially arbitrary ways that code can reach any of the labels, it needs to add code to save and restore register state between statements, which totally wrecks the performance. Another problem is that it doesn’t sort out exactly well is block boundary effects, where you are vastly better off getting your transfers to use aligned instructions.  
No doubt it looks really neat, and I remember a colleague being really impressed with it, but when I worked though it all, I pulled it out of the code again. With any modern language and compiler the single best thing you can do is to express what you mean, not what you think the code should look like.  
Tuning block copy code is a bit of an art, and is best left to someone who is intimately familiar with the processor to code up and put in the language libraries.

---

<div class="post-metadata">

**Author:** ![LSLGuy](https://sea3.discourse-cdn.com/straightdope/user_avatar/boards.straightdope.com/lslguy/32/5813_2.png) [@LSLGuy](https://boards.straightdope.com/u/LSLGuy)\
**Post date:** [December 15, 2017, 3:57pm UTC](https://boards.straightdope.com/t/is-p-q-exactly-the-same-as-p-q/804388/68 "2017-12-15T15:57:05Z")

</div>

> [@Francis\_Vaughan](#):
>
> …  
> No doubt it looks really neat, and I remember a colleague being really impressed with it, but when I worked though it all, I pulled it out of the code again. With any modern language and compiler the single best thing you can do is to express what you mean, not what you think the code should look like.  
> Tuning block copy code is a bit of an art, and is best left to someone who is intimately familiar with the processor to code up and put in the language libraries.

This. It reminds me of the APL one-liners I was so fond of as an undergrad. Not smart.

The esteemed Raymond Chen has a number of blog posts on the fact that modern optimizing compilers do so much stuff you’ve never thought of that any attempt to get cute with your high level language syntax (and yes, C is a high level language) just risks fooling the compiler, not optimizing the instruction stream.

---

<div class="post-metadata">

**Author:** ![TriPolar](https://sea3.discourse-cdn.com/straightdope/user_avatar/boards.straightdope.com/tripolar/32/3008_2.png) [@TriPolar](https://boards.straightdope.com/u/TriPolar)\
**Post date:** [December 15, 2017, 4:18pm UTC](https://boards.straightdope.com/t/is-p-q-exactly-the-same-as-p-q/804388/69 "2017-12-15T16:18:00Z")

</div>

C is pretty close to assembly language and often used that way. A lot of the C code I work with was converted from old assembler and barely looks like C. When efficiency is paramount you may need some cryptic coding, but there are these things called comments and documentation that can prevent that from being a problem. The practical rules for systems code may be quite different from those for application code.

For the constructs that use && to short circuit and protect a reference, like “(p && \*p)” can be coded into a macro to prevent future problems.

---

<div class="post-metadata">

**Author:** ![eschereal](https://sea3.discourse-cdn.com/straightdope/user_avatar/boards.straightdope.com/eschereal/32/18939_2.png) [@eschereal](https://boards.straightdope.com/u/eschereal)\
**Post date:** [December 15, 2017, 4:36pm UTC](https://boards.straightdope.com/t/is-p-q-exactly-the-same-as-p-q/804388/70 "2017-12-15T16:36:38Z")

</div>

Yes, compilers have improved immensely since even the '90s. I remember looking at machine code in the old days and seeing excessive loads and stores and reloads of the same value, but now you can write ridiculously verbose code in C and the compiler will figure out how to scrape it down to the least amount of object code. Sometimes a variable will not even appear in the debugger because its 3 lines of existence got merged into what in the old days you would have written as a bulky expression several layers deep.

Verbosity in source is a good thing.

---

<div class="post-metadata">

**Author:** ![LSLGuy](https://sea3.discourse-cdn.com/straightdope/user_avatar/boards.straightdope.com/lslguy/32/5813_2.png) [@LSLGuy](https://boards.straightdope.com/u/LSLGuy)\
**Post date:** [December 15, 2017, 4:43pm UTC](https://boards.straightdope.com/t/is-p-q-exactly-the-same-as-p-q/804388/71 "2017-12-15T16:43:00Z")

</div>

Before mid 2000’s optimizing compilers I’d agree with 100% of what you (ETA **TriPolar** ) say. And yes, there is C out there which is a thinly warmed over port from earlier assembler.

The big point is that nowadays when efficiency is paramount you choose a good algorithm, pay attention to operand alignment and locality, code it straight forwardly, and let the compiler do magic shit mere humans are nowhere near smart enough to do. Except in very isolated environments with frankly weak toolchains, the compiler is much better at optimizing for hardware performance than even a journeyman of decades’ experience.

---

<div class="post-metadata">

**Author:** ![Derleth](https://avatars.discourse-cdn.com/v4/letter/d/b9e5f3/32.png) [@Derleth](https://boards.straightdope.com/u/Derleth)\
**Post date:** [December 15, 2017, 4:46pm UTC](https://boards.straightdope.com/t/is-p-q-exactly-the-same-as-p-q/804388/72 "2017-12-15T16:46:05Z")

</div>

> [@LSLGuy](#):
>
> C is a high level language

C is a mid-level language, in that it forces you to manage your own memory.

That isn’t a knock on C, it’s just a statement of where it’s most useful: Not at the very lowest level, where assembly is required for machine-specific opcodes, nor at the very highest level, where programmer productivity is most important, but in-between, where memory usage is more important than productivity and time is going to be taken to track down memory leaks and buffer overrun bugs.

---

<div class="post-metadata">

**Author:** ![TriPolar](https://sea3.discourse-cdn.com/straightdope/user_avatar/boards.straightdope.com/tripolar/32/3008_2.png) [@TriPolar](https://boards.straightdope.com/u/TriPolar)\
**Post date:** [December 15, 2017, 5:27pm UTC](https://boards.straightdope.com/t/is-p-q-exactly-the-same-as-p-q/804388/73 "2017-12-15T17:27:09Z")

</div>

> [@LSLGuy](#):
>
> Before mid 2000’s optimizing compilers I’d agree with 100% of what you (ETA **TriPolar** ) say. And yes, there is C out there which is a thinly warmed over port from earlier assembler.
> 
> The big point is that nowadays when efficiency is paramount you choose a good algorithm, pay attention to operand alignment and locality, code it straight forwardly, and let the compiler do magic shit mere humans are nowhere near smart enough to do. Except in very isolated environments with frankly weak toolchains, the compiler is much better at optimizing for hardware performance than even a journeyman of decades’ experience.

In our case we have a complex situation where we have to compile our system for multiple platforms and avoid a few cases where the optimizing magic is a problem. But a lot of it is just holdover from the days of yore. Nobody’s going to go through the effort of rewriting the old code converted to C over 20 years ago. It’s not wise IMHO, but only a handful of people ever touch that code.

Application programmers should definitely not be concerned with execution efficiency at the code level, it is a compiler issue. And in the vast majority of modern applications localized execution efficiency is rarely a concern anyway, we are far more bound by communication and disk bandwidth than anything else.

---

<div class="post-metadata">

**Author:** ![gnoitall](https://avatars.discourse-cdn.com/v4/letter/g/bb73d2/32.png) [@gnoitall](https://boards.straightdope.com/u/gnoitall)\
**Post date:** [December 15, 2017, 6:32pm UTC](https://boards.straightdope.com/t/is-p-q-exactly-the-same-as-p-q/804388/74 "2017-12-15T18:32:40Z")

</div>

> [@LSLGuy](#):
>
> Which language and processor are you discussing? Rest assured some of what you assert is 100% true in some environments, 100% false in others, and 50/50 true & false in yet another group.
> 
> Which is really the big point of the thread: These details matter. Be explicit. Or be buggy. There is no third choice.

Using a Boolean or operator, I can be explicitly buggy. That is truth-equivalent, after all.

---

<div class="post-metadata">

**Author:** ![eschereal](https://sea3.discourse-cdn.com/straightdope/user_avatar/boards.straightdope.com/eschereal/32/18939_2.png) [@eschereal](https://boards.straightdope.com/u/eschereal)\
**Post date:** [December 15, 2017, 6:50pm UTC](https://boards.straightdope.com/t/is-p-q-exactly-the-same-as-p-q/804388/75 "2017-12-15T18:50:17Z")

</div>

> [@Derleth](#):
>
> C is a mid-level language, in that it forces you to manage your own memory.

Not necessarily. In Apple’s Objective-C at the very least, you can use an implicit memory management scheme that relies on llvm to track allocated entities and figure out when they need to be disposed of. Which works better in an OOP environment than in a raw-C type environment, I would imagine.

---

<div class="post-metadata">

**Author:** ![Derleth](https://avatars.discourse-cdn.com/v4/letter/d/b9e5f3/32.png) [@Derleth](https://boards.straightdope.com/u/Derleth)\
**Post date:** [December 15, 2017, 7:37pm UTC](https://boards.straightdope.com/t/is-p-q-exactly-the-same-as-p-q/804388/76 "2017-12-15T19:37:07Z")

</div>

> [@eschereal](#):
>
> Not necessarily. In Apple’s Objective-C at the very least, you can use an implicit memory management scheme that relies on llvm to track allocated entities and figure out when they need to be disposed of. Which works better in an OOP environment than in a raw-C type environment, I would imagine.

Well, that’s Objective-C, not C. It’s compatible with C, to some extent, but it isn’t C.

---

<div class="post-metadata">

**Author:** ![TriPolar](https://sea3.discourse-cdn.com/straightdope/user_avatar/boards.straightdope.com/tripolar/32/3008_2.png) [@TriPolar](https://boards.straightdope.com/u/TriPolar)\
**Post date:** [December 15, 2017, 7:48pm UTC](https://boards.straightdope.com/t/is-p-q-exactly-the-same-as-p-q/804388/77 "2017-12-15T19:48:04Z")

</div>

From what I’ve seen with C used at the OO level, C++, C#, Objective-C, etc., most of the memory management is already in place or handled automatically. I don’t use those languages much though, I see it mainly in our customer’s applications, and almost all of it is rather pedestrian data processing.

---

<div class="post-metadata">

**Author:** ![Derleth](https://avatars.discourse-cdn.com/v4/letter/d/b9e5f3/32.png) [@Derleth](https://boards.straightdope.com/u/Derleth)\
**Post date:** [December 15, 2017, 7:51pm UTC](https://boards.straightdope.com/t/is-p-q-exactly-the-same-as-p-q/804388/78 "2017-12-15T19:51:02Z")

</div>

> [@TriPolar](#):
>
> From what I’ve seen with C used at the OO level, C++, C#, Objective-C, etc., most of the memory management is already in place or handled automatically. I don’t use those languages much though, I see it mainly in our customer’s applications, and almost all of it is rather pedestrian data processing.

Yeah, Java, C#, C++, and Objective-C aren’t C. The fact they work differently from C is how you know.

---

<div class="post-metadata">

**Author:** ![LSLGuy](https://sea3.discourse-cdn.com/straightdope/user_avatar/boards.straightdope.com/lslguy/32/5813_2.png) [@LSLGuy](https://boards.straightdope.com/u/LSLGuy)\
**Post date:** [December 15, 2017, 7:57pm UTC](https://boards.straightdope.com/t/is-p-q-exactly-the-same-as-p-q/804388/79 "2017-12-15T19:57:02Z")

</div>

Not meaning to trigger a debate on high vs mid-level. For sure C was originally conceived as almost syntactic sugar over assembler on a generic early 1970s CPU design.

But my point is that as we get to superscalar pipelined multicore CPUs, optimizing compilers, and all the rest, the actual flow of micro-ops in the instruction pipelines & the data flow in register banks resembles that generic 1970s TTL CPU very very little.

The language features themselves haven’t moved up from mid to high. What has happened in the underlying silicon has migrated into the next time zone so the original almost one-to-one correspondence between C idioms and hardware has become tenuous to the breaking point.

IOW, the quantity of abstraction between modern standards-compliant C and the transistors in a modern CPU is vastly larger than the corresponding quantity in 1980. Pretending you’re still writing very close to the silicon is pretending.

With the notable exceptional of some legacy situations such as **TriPolar** points out a few posts ago.

---

<div class="post-metadata">

**Author:** ![Voyager](https://sea3.discourse-cdn.com/straightdope/user_avatar/boards.straightdope.com/voyager/32/133_2.png) [@Voyager](https://boards.straightdope.com/u/Voyager)\
**Post date:** [December 15, 2017, 8:15pm UTC](https://boards.straightdope.com/t/is-p-q-exactly-the-same-as-p-q/804388/80 "2017-12-15T20:15:01Z")

</div>

> [@Mr.Nylock](#):
>
> I get that they’re equivalent - if something is not p and also not q it is saying it is neither p nor q, like it it’s not both things at once. But is it also the same as saying if p is not true and q is not true then the statement is false? They seem to have the same result when applied to integers - in essence the statement is meaningless if p and q are replaced with two different integers. The statement could have some meaning if p and q were the same integer, although it would be a needlessly bulky way to express negation. If applied to something other than a numeric expression is there any instance or instances where these two booleans things would have a different result when applied to the same variables?

Having been involved with hardware design as well as programming, I can tell you that this is taught in about the second week of logic design 1.  
In the real world !(p && q) can be done in one NAND gate. The other form uses two inverters and an OR. However, if the p and q coming from driving gates are inverted anyhow, the second form might be cheaper, Especially if the output is used inverted, in which case you can use a NOR. NANDs and NORs are usually smaller than ANDs and ORs thanks to the way the circuit design is done.  
Hardware doesn’t have side effects we see in code sometime, and there are no short circuits - though everything is done naturally in parallel.

[Previous page](https://boards.straightdope.com/t/is-p-q-exactly-the-same-as-p-q/804388.md?page=3)

[Next page](https://boards.straightdope.com/t/is-p-q-exactly-the-same-as-p-q/804388.md?page=5)
