Boolean help

Thread Starter

ApacheKid

Joined Jan 12, 2015
1,095
I think there was a time when I could have done this in my sleep, but not today.

Look

Code:
if M = false then
   E = R;
else
   E = N;
All four values are booleans, I want a single expression in M, R and N that evaluates E in the same way as that simple IF stmt, I want E as a logical function of M, R and N.

I've been staring at this for an hour and have brain freeze now.
 
Last edited:

WBahn

Joined Mar 31, 2012
27,946
Several ways to go about it.

The simplest, most brute force way is to just make a truth table.

Code:
M R N E
0 0 0 0
0 0 1 0
0 1 0 1
0 1 1 1
1 0 0 0
1 0 1 1
1 1 0 0
1 1 1 1
From this you have

E = M'RN' + M'RN + MR'N + MRN

This simplifies very readily
E = M'R(N' + N) + MN(R' + R)
E = M'R + MN

An if/else statement also maps to a 2:1 multiplexer in which M is fed to the select input and R is fed to the input that is selected when M is FALSE and N is fed to the other input. Notice that this is exactly the logic described by the equation for E above.

This same result can be obtained just by asking what the if/else statement is really saying:

IF (M=0), then E is whatever R happens to be, otherwise it is whatever N happens to be.

An AND gate is a way of selectively forcing a signal to be LO when a control signal is LO and letting it pass when the control signal is HI.

So the expression M'R is LO whenever M is HI and equal to R when M is LO. Similarly, MN is LO whenever M is LO and equal to N when M is HI.

An OR gate allows one signal to pass provided the other signal is LO.

Hence, the logic described above.
 
Last edited:

Thread Starter

ApacheKid

Joined Jan 12, 2015
1,095
Several ways to go about it.

The simplest, most brute force way is to just make a truth table.

Code:
M R N E
0 0 0 0
0 0 1 0
0 1 0 1
0 1 1 1
1 0 0 0
1 0 1 1
1 1 0 0
1 1 1 1
From this you have

E = M'RN' + M'RN + MR'N + MRN

This simplifies very readily
E = M'R(N' + N) + MN(R' + R)
E = M'R + MN

An if/else statement also maps to a 2:1 multiplexer in which M is fed to the select input and R is fed to the input that is selected when M is FALSE and N is fed to the other input. Notice that this is exactly the logic described by the equation for E above.
Thanks, that's helpful, so in terms of say C with |, & and ^ etc, what is the expression?
 

WBahn

Joined Mar 31, 2012
27,946
Thanks, that's helpful, so in terms of say C with |, & and ^ etc, what is the expression?
Depends on the values involved. When you say that are Boolean, does that mean that they are always precisely 0 or 1, or just 0 or non-0?

If they are just expressions treated as logical values (i.e., 0 or non-0), then you need to use the logical operators (not the bitwise operators).

E = ((!M) && R) || (M && N);

I wouldn't think that this would be that difficult for someone that has written compilers before.

If they are exactly 0 or 1, then you can use the bitwise operators, but you need to (in general) mask out the non-used bits at the end.

E = ( ((~M) & R) | (M & N) ) & 0x01;

However, the final masking operating is not needed in this case because this particular logic always forces the other bits to be zero.
 

WBahn

Joined Mar 31, 2012
27,946
Is this the same as:

E = (M & !R) | (M & N)

?
No, that definitely won't work. If M is LO, that kills both terms and E will be LO. If M is HI, then the result will be HI if either R is LO or N is HI.

E = (!M & R) | (M & N)

This is possibly what you meant, and it is close. But you are mixing logical and bitwise operations and that is dangerous. It depends on where the information is encoded. You need to consider the difference between bitwise operations and logical operations very carefully in light of exactly how your information is represented. If M, N, and R are simply specific bits in an integer field, the !R may not have the effect you want, because it will produce a 0 result if ANY of the bits in R happen to be set.
 

WBahn

Joined Mar 31, 2012
27,946
A potentially better alternative is to use the conditional operator.

E = M? N : R;

Many compilers can recognize this pattern and match it to particular hardware capabilities on the target machine.
 

Thread Starter

ApacheKid

Joined Jan 12, 2015
1,095
Depends on the values involved. When you say that are Boolean, does that mean that they are always precisely 0 or 1, or just 0 or non-0?

If they are just expressions treated as logical values (i.e., 0 or non-0), then you need to use the logical operators (not the bitwise operators).

E = ((!M) && R) || (M && N);

I wouldn't think that this would be that difficult for someone that has written compilers before.

If they are exactly 0 or 1, then you can use the bitwise operators, but you need to (in general) mask out the non-used bits at the end.

E = ( ((~M) & R) | (M & N) ) & 0x01;

However, the final masking operating is not needed in this case because this particular logic always forces the other bits to be zero.
No, that definitely won't work. If M is LO, that kills both terms and E will be LO. If M is HI, then the result will be HI if either R is LO or N is HI.

E = (!M & R) | (M & N)

This is possibly what you meant, and it is close. But you are mixing logical and bitwise operations and that is dangerous. It depends on where the information is encoded. You need to consider the difference between bitwise operations and logical operations very carefully in light of exactly how your information is represented. If M, N, and R are simply specific bits in an integer field, the !R may not have the effect you want, because it will produce a 0 result if ANY of the bits in R happen to be set.
I wrote & and | in the boolean algebra sense, what combination of logic gates would compute the result bit E.
 

WBahn

Joined Mar 31, 2012
27,946
I wrote & and | in the boolean algebra sense, what combination of logic gates would compute the result bit E.
Let me be more specific:

E = M'R + MN

is pretty widely understood notation for the following Boolean operations:

E = (NOT(M) AND R) OR (M AND N)

You specifically asked about the C operators |, & and ^, and others.
|, &, ^, and ~ are bitwise operators.
||, &&, and ! are logical operators.

They are NOT the same and you can't just replace the Boolean operators in the above expression for E with them and expect it to work. Whether they do what you want depends on how your Boolean values are represented. C does not have a Boolean data type, so your value will either be represented as an integer value using an entire integer, or they will be represented as a particular bit within an integer value. It matters which.
 

Thread Starter

ApacheKid

Joined Jan 12, 2015
1,095
Let me be more specific:

E = M'R + MN

is pretty widely understood notation for the following Boolean operations:

E = (NOT(M) AND R) OR (M AND N)

You specifically asked about the C operators |, & and ^, and others.
Well with all due respect this is the question I asked, with added emphasis:

All four values are booleans, I want a single expression in M, R and N that evaluates E in the same way as that simple IF stmt, I want E as a logical function of M, R and N.
In other words that IF statements is merely a problem definition, describing the goal, not meant to imply anything more than that.

|, &, ^, and ~ are bitwise operators.
||, &&, and ! are logical operators.
Yes, and I'm not disputing that, but it's immaterial to my question.

They are NOT the same and you can't just replace the Boolean operators in the above expression for E with them and expect it to work. Whether they do what you want depends on how your Boolean values are represented. C does not have a Boolean data type, so your value will either be represented as an integer value using an entire integer, or they will be represented as a particular bit within an integer value. It matters which.
Perhaps expressing the problem in pseudo code was not a good idea, it seems to have led to confusion and so I apologize for that.

I want bitwise operators, I'm ultimately "anding" and "oring" bytes of storage, I think you already answered me too, the first principles truth table is the place to start, its been decades since I did anything with boolean logic like this so of course I'm rusty.

Thanks.
 

Thread Starter

ApacheKid

Joined Jan 12, 2015
1,095
Your bare bones raw truth table is the way to go, as I said I'm rusty but recall now that this is the brute force way to express E in terms of the other bits.

If you're curious about why I asked, it's a way for me to use the various nRF24 register structs to be able to set/unset specific bits in a register.

Rather than some convoluted API where we pass bit positions around, I can do this:

Code:
void update(NrfReg_RF_SETUP R, NrfReg_RF_SETUP N, NrfReg_RF_SETUP M, NrfReg_RF_SETUP_ptr E)
{
    uint8_t r = *(uint8_t*)(&(R));
    uint8_t n = *(uint8_t*)(&(N));
    uint8_t m = *(uint8_t*)(&(M));
   
    uint8_t e = (~m & r & ~n) | (~m & r & n) | (m & ~r & n) | (m & r & n);

    *((uint8_t*)(E)) = e;
}
So in a test we get:

1667840694479.png

The name means R = "the register's current value", N = "the new values of bits to set in the register", M = "mask" - the specific bits we want to change and E "end result" - the register's final value.

So in the above the request was to set the RF_DR_HIGH bit and set it to OFF.

So by setting specific bit in M we can tell the API which bits are to be changed, where M has an OFF bit, we simply leave that register bit unchanged.

Of course that boolean expression can be made into a macro.
 

WBahn

Joined Mar 31, 2012
27,946
As indicated in that first response,

uint8_t e = (~m & r & ~n) | (~m & r & n) | (m & ~r & n) | (m & r & n);

is unnecessarily complicated (and slow). An equivalent expression is

uint8_t e = (~m & r) | (m & n);
 

Thread Starter

ApacheKid

Joined Jan 12, 2015
1,095
As indicated in that first response,

uint8_t e = (~m & r & ~n) | (~m & r & n) | (m & ~r & n) | (m & r & n);

is unnecessarily complicated (and slow). An equivalent expression is

uint8_t e = (~m & r) | (m & n);
Yes, you're right, I could kind of see that but got different result then just found an error - so many parentheses in my macros...

Many thanks, I now have an API that can read, write and flexibly update any nRF24 register, the basis for me to proceed with some proper nRF code now...
 

Thread Starter

ApacheKid

Joined Jan 12, 2015
1,095
Here's how it pans out:

Code:
    NrfReg_STATUS status;
    NrfReg_RF_SETUP setup = { 0 };
    NrfReg_RF_SETUP mask = { 0 };
    
    setup.PLL_LOCK = 1;
    setup.RF_DR_LOW = 0;
    setup.CONT_WAVE = 0;
    
    mask.PLL_LOCK = 1;
    mask.RF_DR_LOW = 1;
    mask.CONT_WAVE = 1;
    
    nrf24_package.UpdateRegister.RF_SETUP(&device, setup, mask, &status);
So whatever is currently in the register will remain, except the PLL_LOCK will get set to 1, RF_DR_LOW will get set to 0 and CONT_WAVE will get set to 0.

Many of the examples of this kind of thing, that I've seen pass clumsy bit numbers in, like this, this requires multiple calls if multiple fields are to be updated:

Code:
void NRF_cmd_modify_reg(uint8_t reg, uint8_t bit, uint8_t state)
{
    // thhis is a "read-modify-write" procedure 
    
    //READ
    uint8_t reg_value =  NRF_cmd_read_single_byte_reg(reg);
    
    //MODIFY
    if (state)
    {
        reg_value |= (1 << bit);
    }
    else
    {
        reg_value &= ~(1 << bit);
    }
        
    //WRITE
    NRF.NRF_CSN_LOW();    
    
    NRF.spiSend(reg | W_REGISTER);      //write data register
    NRFSTATUS = NRF.spiRead();
    
    NRF.spiSend(reg_value); 
    NRFSTATUS = NRF.spiRead();

    NRF.NRF_CSN_HIGH();
 
Top