Connection between ternary logic and mux logic? - c

I'm implementing a computer simulator in C with the challenge not to use conditionals (ie no if/else, switch/case, while/for, etc.). There are a lot of muxes in the hardware I'm simulating, so it would be nice if I could use the conditional ternary logic operators. So, my question: do C compilers create MUX logic from ternary logic operators, or do they create branches?
Example:
int a, b, q, r;
/* Ternary logic */
r = q ? a : b;
/* MUX equivalent logic */
r = ( q & a ) | ( (~q) & b )
/* Branch equivalent logic */
if (q) r = a; else r = b;

The ternary operator is equivalent to a branch: i.e. the value not returned is not evaluated.
I don't know how much you are constrained, so note that boolean operators && and || don't evaluate their second argument is the result can be determined from the first.
(And note that you line "MUX" doesn't something very different from the other two expressions: it select bits from a or b depending on the value of corresponding bit in q, it doesn't select a or b depending if q is null or not; Edit: it is worse: you are using !q and not ~q...).

C compilers create branches out of ternary statements.
Using Freescale's Codewarrior IDE, I compiled the following C program:
int a, b, q, r;
void main(void) {
a = 0;
b = 1;
q = 0;
r = q ? a : b;
..
..
}
The assembly corresponding to the ternary statement is as follows:
...
LDX 0x1104 ; load val[q] into register x
BNE *+4 ; branch to abs addr 0xC016 if val[q]==a
BRA *+5 ; branch to abs addr 0xC019 if val[q]!=a
...

Often, branching logic is created, but is very possible to do ternary operation without any kind of branch if you're fine with both values being evaluated. Consider this:
#include <stdio.h>
static inline int isel(int cond, int a, int b)
{
int mask = cond | (-cond);
mask >>= 31;
return (b & mask) | (a & ~mask);
}
int main(void)
{
printf("1 ? 3 : 4 => %d\n", isel(1, 3, 4));
printf("0 ? 3 : 4 => %d\n", isel(0, 3, 4));
printf("-1 ? 3 : 4 => %d\n", isel(-1, 3, 4));
return 0;
}
This code assumes that right-shifting of signed numbers will sign-extend, and that sizeof(int) == 4.
Some processors can do isel() as an assembly instruction. However, both values will be evaluated, which the ternary ?: doesn't do.
Depending on the situation, the compiler will generally try to do the fastest thing, either branching to avoid redundant calculation, or doing this kind of logic if values in the ternary expression are simple.

Related

Does macro function with operator precedence show unusual result?

#define SQUARE(x,y) (x<y?x:y)
int a = 5, b = 6, c = 3;
int var = SQUARE(a & c,b);
I have searched and learnt that '<' precede '&'. As per rules it should give '5'. But it is giving output as '1'. But in some cases it is giving right output. Can you please explain macro rules of this and what am I missing here.
Macros are just replaced by the preprocessor, so the arguments are not evaluated and then passed like in functions.
In your example the expression SQUARE(a & c, b); will become (a & c < b ? a & c : b);
For a=5, b=6, c=3 it evaluates to:
(5 & 3<6 ? 5&3 : 6) //'<' precede '&' as you correctly mentioned
(5&1 ? 5&3 : 6) // '3 < 6' is a boolean expression which evaluates to 1. '&' is bitwise AND.
(1 ? 1 : 6)
(1)
So 1 is the right output.
EDIT:
A good aproach is to always use parentheses around your arguments and the whole expression to eliminate the problem of operator precedence.
As mention by others it can be dangerous to use macros due to multiple evaluation, which may not only effect performance.
For example:
#define SQUARE(x) ((x)*(x))
seems to only square the argument, but if you call it like
f = SQUARE(x++);
you will get undefined behaviour. A better approach for small function would be to declare it as inline.
inline int square(int x)
{
return x*x;
}
Also as mentioned by #EricPostpischil macros are not a textual replacement as the preprocessor replaces by tokens.
For example:
#define a 1
#define b 2
printf("%d\n", ab);
here ab is not replaced with 12 as someone would expect for pure textual replacement.
Macros require parentheses as they are not functions and just do the textual replacement
#define SQUARE(x,y) (((x)<(y))?(x):(y))
The macro is extremely side effects error and UB prone:
Example: SQUATE(x++,y)
in your example 5 & 3 will be evaluated every time you have the x in your macro. It will be less effective than the inline function
inline unsigned SQUARE(unsigned x, unsigned y)
{
return (x < y) ? x : y;
}
In a bit more detail, as #P__J__ said, macros are just text replacement by the pre-processor, not functions. So this:
#define SQUARE(x,y) (x<y?x:y)
int a = 5, b = 6, c = 3;
int var = SQUARE(a & c,b);
is translated to:
int a = 5, b = 6, c = 3;
int var = (a & c<b?a & c:b);
Because every x is replaced with a & c and every y is replaced with b.
If you also apply the values as in #Osiris 's answer, you'll get:
int var = (5 & 3 < 6 ? 5 & 3 : 6);
At this point, as you already said, < takes precedence over &.
The result of < is true or false, which means 1 or 0, so 3 < 6 becomes 1.
The result of & is the bitwise AND between two numbers, which in this case is also 1 (because 5 is 101 and 3 is 011).
This is why it becomes
(5 & 1 ? 1 : 6)
That next 5 & 1 will also become 1 (because of the AND between 101 and 001), so you'll get:
(1 ? 1 : 6)
And since 1 is true, you'll get the first value, which is also a 1.
Also, as already pointed out, be careful with evaluation in a macro.
These are just numbers and you're already seeing some not so obvious behaviour, but if had passed a function as one of the arguments, that function would've run multiple times.
For example
#define SQUARE(x,y) (x<y?x:y)
int var = SQUARE(update_counter(a), 1);
would have been translated to
int var = (update_counter(a) < 1 ? update_counter(a) : 1);
Thus potentially updating a hypothetical counter twice.

Rewriting a piece of C code without conditional statements or operators?

I was in a technical interview where the interviewer gave me a piece of code like this
int a=1;
a++;
...something..
...something.
if(a==25)
a=0;
he said me to rewrite this code without using switch,if else or ternary operator for the if condition. How it can be done?
It's quite simple actually:
a *= (a != 25);
This will multiply a by 0 if a is equal to 25, else it will multiply a by 1.
If you're also not allowed to test for equality then here is a fully arithmetic way:
unsigned int v = a - 25;
/* test for bits set and put result in lsb of v */
v |= v >> 16;
v |= v >> 8;
v |= v >> 4;
v |= v >> 2;
v |= v >> 1;
/* set a to a if lsb of v is 1, else set to 0 */
a *= v & 1;
a != 25 || (a = 0);
This does not use "switch,if else or ternary operator"
The question, as posed, gives undefined behaviour since you are using an uninitialised variable. Therefore you are free to write any code you like (so long as it compiles).
See C standard 6.3.2.1p2:
If the lvalue designates an object of automatic storage duration that
could have been declared with the register storage class (never had
its address taken), and that object is uninitialized (not declared
with an initializer and no assignment to it has been performed prior
to use), the behavior is undefined.
That, in my opinion, is the smart answer: although you would be wise to be graceful when answering a question in this way.
Remember that assignment is just an ordinary expression, and as such can be used as part of another expression. For example you could use the short-circuit logical and operator:
a == 25 && (a = 0);
You need to put parenthesis around the assignment because assignment has lower precedence than the && operator.
Another interesting answer could be
for ( ; a == 25 ; ) {
a = 0; break;
}
This does not use 'if-else', 'switch' or 'ternary operator'
If the context implied is a counting loop where a always repeats the cycle 0..24, then perhaps a mathematically more appealing solution would be
a = (a+1) % 25;
But this of course wouldn't work in a sitation where a can be anything, and it should only be reset in case of a==25, while something a==26 should be left alone.
The interviewers might like it though, if you search for a "semantic" solution like that, and can explain when to use this.
I think interviewer wanted you to use this line instead of if:
a %= 25;

Write a C function that round up a number to next power of 2

I got the following question in an interview: "Write a C function that round up a number to next power of 2."
I wrote the following answer:
#include <stdio.h>
int next_pwr_of_2(int num)
{
int tmp;
do
{
num++;
tmp=num-1;
}
while (tmp & num != 0);
return num;
}
void main()
{
int num=9;
int next_pwr;
next_pwr=next_pwr_of_2(num);
printf(" %d \n",next_pwr);
}
The question is: why does the program go out of its do-while loop when getting to the values 11 and 10?
Precedence my friend, precedence.
while ((tmp & num) != 0);
Will fix it. ( note the parenthesis around the expression tmp & num)
!= has higher precedence than &, so num != 0 is evaluated before tmp & num.
If you skip the parenthesis, the expression that is evaluated is : tmp & (num != 0)
First time round, tmp = 9 (1001) and num != 0 is 1 (0001) so & evaluates to 1 (true), and the loop continues.
Now at the end of second iteration, we have, tmp = 10 (1010). num != 0 is again 0001, so 1010 & 0001 evaluates to 0, hence the loop breaks.
Here is the table for reference.
The precedence order is quite unusual, as noted here. Happens all the time :).
Of course you don't have to remember any precedence order, which is just to help the compiler in deciding what is done first if the programmer does not make it clear. You can just correctly parenthesize the expression and avoid such situations.
The loop exits because you did not put parentheses around your condition. This should teach you not to put the unnecessary != 0 in your C/C++ conditions.
You can simplify your code quite a bit, though.
First, observe that temp equals the prior value of num, so you can change your loop to
int tmp;
do {
tmp = mum++;
} while (tmp & num); // Don't put unnecessary "!= 0"
Second, the interviewer was probably looking to see if you are familiar with this little trick:
v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v++;
Unlike your code that may take up to 1,000,000,000 operations to complete, the above always completes after twelve operations (a decrement, an increment, five shifts, and five ORs).
Such questions always deserve counter questions to clarify requirements, if only to demonstrate your thinking and analytical skills and even creativity - that is what the interview should be about.
For example in the absence of any specification that the "number" in question is necessarily an integer, you might propose the following:
int nextPow2( double x )
{
return (int)pow( 2, ceil(log10(x) / log10(2))) ;
}
But if you did you might also express concern about the applicability of such a solution to an embedded system with possibly no floating-point unit.
I would answer by saying no one should write that in pure C. Especially in an embedded environment. If the chipset does not provide a feature to count the number of leading zeros in a word, then it's probably pretty old, and certainly not something you want to be using. If it does, you would want to use that feature.
As an example of a non-standard way to round an unsigned integer up to a power of two (you really need to clarify the type of the argument, as "number" is ambiguous) using gcc, you could do:
unsigned
round_up( unsigned x )
{
if( x < 2 ) {
return 1U;
} else {
return 1U << ( CHAR_BIT * sizeof x - __builtin_clz( x - 1 ));
}
}
In contrast to what others have said, the bit-twiddling trick actually can be used on any number of bits portably. Just change it a bit:
unsigned int shift = 1;
for (v--; shift < 8 * sizeof v; shift <<= 1)
{
v |= v >> shift;
}
return ++v;
I believe any compiler will optimize the loop away, so it should be the same performence-wise (plus I think it looks better).
Yet another variant.
int rndup (int num)
{
int tmp=1;
while (tmp<num)
{
tmp*=2;
}
return tmp;
}
Another variant using while loop and bit-wise operator
int next_pwr_of_2(unsigned &num)
{
unsigned int number = 1;
while (number < num)
{
number<<=1;
}
return number;
};

multiplication in C without arithmetic operators

Is it possible to multiply two numbers with out using arithmetic operators using C? Using the left shift operator, I can multiply any number by 2 only. How about other numbers?
To solve this problem, the first thing you want to do is figure out how to get simple arithmetic operations using just bitwise operators.
For example, addition can be achieved using this technique
int add(int a, int b) {
int c;
while (a != 0) {
c = b & a;
b = b ^ a;
c = c << 1;
a = c;
}
return b;
}
Then it's a matter of doing multiplication using addition:
int mult(int a, int b) {
int i = 0;
int c = 0;
while (i < b) {
c = add(c, a);
i = add(i, 1);
}
return c;
}
This multiplication doesn't yet work if b is negative, but since this looks like a homework problem, I'll leave that as an exercise for you. ;)
Edit:
While multiplication is intuitive once you have addition, the addition function is not so easy to understand, so I'll explain it here.
Let's say you want to add two numbers, 11010011 and 10101. The usual way to do it is to line them up like so:
11010011
+ 10101
You'll notice that when you add two binary numbers, if the ith bit from both numbers is 1, then the resulting bit is 0, and there is a carry over to a bit to the left of i.
This carry is what the variable 'c' in the code stores.
//...
c = b & a;
//...
c << 1;
//...
We bit wise and b and a to get only the bits where both a and b are 1, then we left shift it by 1 to get the carry bits.
Then you can look at the bits where a and b differ, i.e. one of the bits is 1 and the other bit is 0. The resulting bit in this case will be 1 with no carry.
that's what this line stores:
b = b ^ a;
The line above essentially removes the bits where both a and b are 1 (now stored in c).
So now you have another two numbers b and c, that you need to add together.
First let's look at where we're at with the example after the first iteration of the loop
c = a = 00100010
b = 11000110
It might not be entirely obvious yet, but b is accumulating the resulting sum. Through more iterations of the loop, more bits that are carried over are "added" back to b, with carries stored again in c. In that sense, you can think of the xor operator as an addition operation without carry.
Here's the second iteration of that loop:
c = a = 00000010
b = 11100100
3rd iteration:
c = a = 00000000
b = 11100110
Now c (and a) is 0, so there is no more carry to add. We exit the loop and return b. Note that even if you continue the loop, none of the numbers will change.
It is possible, see this wiki for a direction: http://en.wikipedia.org/wiki/Binary_multiplier
void main()
{
int n1, n2, n3, n4, x, y, i;
printf("Enter first number");
scanf("%d", &n1);
printf("Enter second number");
scanf("%d", &n2);
n3 = n2;
n4 = n2;
n1-=1;
for(i = n1;i > 0;i-=1)
{
do {
x = n2 & n3;
y= n2 ^ n3;
n2 = x << 1;
n3 = y;
} while (x);
n2 = y;
n3 = n4;
}
printf("product of two number is %d", y);
getch();
}
Yes it is possible. You can do it with logical operators. After all, that's all that the hardware does when you use an arithmetic operator.

Why assignment by Logical Operators ( &&= and ||= ) is missing in C/C++?

1) Why there is no assignment by logical operator like there is assignment by sum and difference?
bool a = true;
bool b = false;
a = a || b;
a ||= b; // syntax error!
a |= b; // OK.
2) What is the meaning of applying bitwise operator on boolean variable?
Is it the same as using logical operator?
It's true that &&= and ||= are "missing" from C. I think one reason is that logical AND and OR in C perform short-circuiting, which would be a little strange in the abbreviated form. But don't use the bitwise assignment operators in their place. Instead, just write:
a = a && b;
c = c || d;
The bitwise operators will work if you have canonical true/false values (1 and 0). But if applied to non-canonical values, such as 5 and 2, you will get different results (5 && 2 is 1, but 5 & 2 is 0).
a |= b means the same as a = (a | b), except that the address of a is evaluated only once. Then you look up the rules for promotion, and for assignment to bool.

Resources