As part of my CS classes I've recently completed the pretty popular "Data Lab" assignments. In these assignments you are supposed to implement simple binary operations in C with as few operations as possible.
For those who are not familiar with the "Data Lab" a quick overview about the rules:
You may not call functions, cast or use control structures (e.g. if)
You may assign variables with no operator cost, however only int is allowed)
The less operators you use, the better
You may assume sizeof(int) == 32
Negative numbers are represented in 2's complement
The task is to implement a logical not called 'bang' (where bang(x) returns !x) by only using the following operators: ~ & ^ | + << >>
The function prototype is defined as
int bang(int x)
The best implementation I could find (using 5 operators) was the following:
return ((x | (~x +1)) >> 31) + 1
However there seems to be a way to accomplish this with even less operators, since I found a result website[1] from some German university where two people apparently found a solution with less than 5 operator. But I can't seem to figure out how they accomplished that.
[1] http://rtsys.informatik.uni-kiel.de/~rt-teach/ss09/v-sysinf2/dlcontest.html (logicalNeg column)
To clarify: This is not about how to solve the issue, but how to solve it with less operations.
Only slightly cheating:
int bang(int x) {
return ((x ^ 0xffffffffU) + 1UL) >> 32;
}
is the only way I can think of to do it in only 3 operations. Assumes a 32-bit int and 64-bit long...
If you take the liberty of assuming that int addition overflow is well-defined and wraps (rather than being undefined behavior), then there's a solution with four operators:
((a | (a + 0x7fffffff)) >> 31) + 1
I think you are assuming that overflow is defined to wrap otherwise your function ((x | (~x + 1)) >> 31) + 1 has undefined behavior for x=INT_MIN.
why not just :-
int bang(int x)
{
return 1 >> x;
}
Related
I'm trying to create a function to determine whether x is less than or equal to y.
The legal operators are ! ~ & ^ | + << >>, and the function says "if x <= y then return 1, else return 0"
My thought process is to check whether x-y is negative, and then right shift 31 bits and compare with 1. No matter what adjustments I do, it returns 0, when it's expecting 1.
This is what I have so far:
int isLessOrEqual(int x, int y) {
return (((x - y) >> 31) & 1) | (!(x^y));
}
Can anyone please help me see what I'm doing wrong?
I also tried with all of these return statements:
return (!(x^y)) | (((x+(~y+1)) >> 31 ) & 1);
return ~(((x+(~y+1)) >> 31 ) & 1) | (!(x^y));
return !(((x+(~y+1)) >> 31 ) & 1) | (!(x^y));
return (((x+(~y+1)) >> 31 ) & 1);
return (((x+y+(~1)) >> 31 ) & 1) | (!(x^y));
return (((x+y+(~1) >> 31 ) & 1) | (!(x^y));
return (((x+(~y+1)) >> 31 ) & 0);
I am not going to do your assignment for you, but I will try to get you pointed in the right direction.
My thought process is to check whether x-y is negative, and then right shift 31 bits and compare with 1.
I take you to mean that you want to test whether x-y is negative by shifting the result and comparing with 1, and then to use that in determining the function's return value. That's more or less ok, but there is some room for concern about right shifting negative numbers, as the result is implementation defined. I do not think that's causing you trouble in practice, however.
No matter what adjustments I do, it returns 0, when it's expecting 1.
In some cases, yes. But there are many other cases where that approach, correctly implemented, produces the desired result. About 75% of cases, in fact. Specifically,
it works (only) when x-y does not overflow.
Additionally,
since you're not allowed to use the - operator, you'll need to perform the two's complement conversion and use + instead.
you can avoid the shifting by ANDing with INT_MIN instead of with 1. This yields a nonzero result (INT_MIN) when and only when the other operand of the & has its sign bit set. If you like, you can convert non-zero to exactly 1 by logically negating twice (!!x).
You can slightly simplify the overall computation by using y-x instead of x-y. Then you don't need special accommodation for the x == y case.
You know (or can know) that neither x - y nor y - x overflows when x and y have the same sign.* In that case, you can use one or another variation on testing the arithmetic difference of the arguments. On the other hand, there is a simpler alternative when the two have differing signs (left as an exercise).
To combine those into a single expression, you can compute bitmasks that effect a selection between two alternatives. Schematically:
return (WHEN_SIGNS_MATCH_MASK(x, y) & IS_DIFFERENCE_NON_NEGATIVE(y, x))
| (WHEN_SIGNS_DIFFER_MASK(x, y) & ...);
The WHEN_SIGNS_MATCH_MASK should evaluate to 0 when the signs differ and to -1 (== all bits 1) or another appropriate value when the signs are the same. The WHEN_SIGNS_DIFFER_MASK implements the opposite sense of that sign comparison. The IS_DIFFERENCE_NON_NEGATIVE expands to your subtraction-based computation, and the ... is the alternative approach for the differing-sign case. (I've implied using macros. You don't need to use macros, but doing so will probably make your code clearer.)
*A sufficient condition, but not a necessary one.
In some old C/C++ graphics related code, that I have to port to Java and JavaScript I found this:
b = (b+1 + (b >> 8)) >> 8; // very fast
Where b is short int for blue, and same code is seen for r and b (red & blue). The comment is not helpful.
I cannot figure out what it does, apart from obvious shifting and adding. I can port without understanding, I just ask out of curiosity.
y = ( x + 1 + (x>>8) ) >> 8 // very fast
This is a fixed-point approximation of division by 255. Conceptually, this is useful for normalizing calculations based on pixel values such that 255 (typically the maximum pixel value) maps to exactly 1.
It is described as very fast because fully general integer division is a relatively slow operation on many CPUs -- although it is possible that your compiler would make a similar optimization for you if it can deduce the input constraints.
This works based on the idea that 257/(256*256) is a very close approximation of 1/255, and that x*257/256 can be formulated as x+(x>>8). The +1 is rounding support which allows the formula to exactly match the integer division x/255 for all values of x in [0..65534].
Some algebra on the inner portion may make things a bit more clear...
x*257/256
= (x*256+x)/256
= x + x/256
= x + (x>>8)
There is more discussion here: How to do alpha blend fast? and here: Division via Multiplication
By the way, if you want round-to-nearest, and your CPU can do fast multiplies, the following is accurate for all uint16_t dividend values -- actually [0..(2^16)+126].
y = ((x+128)*257)>>16 // divide by 255 with round-to-nearest for x in [0..65662]
Looks like it is meant to check if blue (or red or green) is fully used. It evaluates to 1, when b is 255, and is 0 for all lower values.
A common use case of when you'd want to use a formula that's more accurate than 257/256 is when you have to combine a lot of alpha values together for each pixel. As one example, when doing image shrinking, you need to combine 4 alphas for each source pixel contributing to the destination, and then combine all the source pixels contributing to the destination.
I posted an infinitely accurate bit twiddling version of /255 but it was rejected without reason. So I'll add that I implement alpha blending hardware for a living, I write real time graphics code and game engines for a living, and I've published articles on this topic in conferences like MICRO, so I really know what I'm talking about. And it might be useful or at least entertaining for people to understand the more accurate formula that is EXACTLY 1/255:
Version 1: x = (x + (x >> 8)) >> 8
- no constant added, won't satisfy (x * 255) / 255 = x, but will look fine in most cases.
Version 2: x = (x + (x >> 8) + 1) >> 8
- WILL satisfy (x * 255) / 255 = x for integers, but won't hit correct integer values for all alphas
Version 3: (simple integer rounding):
(x + (x >> 8) + 128) >> 8
- Won't hit correct integer values for all alphas, but will on average be closer than Version 2 at the same cost.
Version 4: Infinitely accurate version, to any level of precision desired, for any number of composite alphas: (useful for image resizing, rotation, etc.):
[(x + (x >> 8)) >> 8] + [ ( (x & 255) + (x >> 8) ) >> 8]
Why is version 4 infinitely accurate?
Because 1/255 = 1/256 + 1/65536 + 1/256^3 + 1/256^4 + ...
The simplest expression above (version 1) doesn't handle rounding, but it also doesn't handle the carries that occur from this infinite number of identical sum columns. The new term added above determines the carry out (0 or 1) from this infinite number of base 256 digits. By adding it, you are getting the same result as if you added all the infinite addends. At which point you can round by adding a half bit to whatever accuracy point you want.
Not needed for the OP perhaps, but people should know that you don't need to approximate at all. The formula above is actually more accurate than double precision floating point.
As for speed: In hardware, this method is faster than even a single (full width) add. In software, you have to consider throughput vs latency. In latency, it may still be faster than a narrow multiply (definitely faster than a full width multiply), but in the OP context, you can unroll many pixels at once, and since modern multiply units are pipelined, you are still OK. In translation to Java, you probably have no narrow multiplies, so this could still be faster, but need to check.
WRT the one person who said "why not use the built in OS capabilities for alpha blitting?": If you already have a substantial graphical code base in that OS, this might be a fine option. If not, you're looking at hundreds to thousands as many lines of code to leverage the OS version - code that's far harder to write and debug than this code. And in the end, the OS code you have isn't portable at all, while this code can be used anywhere.
I suspect that it is trying to do the following:
boolean isBFullyOn = false;
if (b == 0xff) {
isBFullyOn = true;
}
Back in the days of slow processors; smart bit-shifting tricks like the above could be faster than the obvious if-then-else logic. It avoids a jump statement which was costly.
It probably also sets an overflow flag in the processor which was used for some latter logic. This is all highly dependant upon the target processor.
And also on my part speculative!!
Is value of b+1 + b/256, this calculation divided by 256.
In that way, using bit shift the compiler tranlte using CPU level shift instruction, instead of using FPU or library division functions.
b = (b + (b >> 8)) >> 8; is basically b = b *257/256 .
I would consider +1 being an ugly hack of the -0.5 mean reduce caused by the inner >>8.
I would write it as b = (b + 128 + ((b +128)>> 8)) >> 8; instead.
Running this test code:
public void test() {
Set<Integer> results = new HashSet<Integer>();
// short int ranges between -32767 and 32767
for (int i = -32767; i <= 32767; i++) {
int b = (i + 1 + (i >> 8)) >> 8;
if (!results.contains(b)) {
System.out.println(i + " -> " + b);
results.add(b);
}
}
}
Produces all possible values between -129 and 128. However, if you are working with 8-bit colours (0 - 255) then the only possible outputs are 0 (for 0 - 254) and 1 (for 255) so it is likely that it is attempting the function #kaykay posted.
What are the purposes of ^ operator used in C other than to check if two numbers are equal? Also, why is it used for equality in stead of == in the first place?
The ^ operator is the bitwise XOR operator. Although I have never seen it's use for checking equaltity.
x ^ y will evaluate to 0 exatly when x == y.
The XOR operator is used in cryptography (en- and decrypting text using a pseudo-random bit stream), random number generators (like the Mersenne Twister) and in inline-swap and other bit twiddling hacks:
int a = ...;
int b = ...;
// swap a and b
a ^= b;
b ^= a;
a ^= b;
(useful if you don't have space for another variable like on CPUs with few registers).
^ is the Bitwise XOR.
A bitwise operation operates on one or more bit patterns or binary numerals at the level of their individual bits. It is a fast, primitive action directly supported by the processor, and is used to manipulate values for comparisons and calculations. (source: Bitwise Operation)
The XOR Operator has two operands and it returns 1 if only one of the operands is set to 1.
So a Bitwise XOR Operation of two numbers is the resulting of these bit by bit operations.
For exemple:
00000110 // A = 6
00001010 // B = 10
00001100 // A ^ B = 12
^ is a bit-wise XOR operator in C. It can be used in bits toggling and to swap two numbers;
x^=y, y^=x, x^=y;
and can be used to find max of two numbers;
int max(int x, int y)
{
return x ^ ((x ^ y) & -(x < y));
}
It can be used to selectively flip bits. (e.g. to toggle the value of bit #3 in an integer, you can say x = x ^ (1<<3) or, more compactly, x = x^0x08 or even x^=8. (although now that I look at it, the last form looks like some sort of obscene emoticon and should probably be avoided. :)
It should never be used in a test for equality (in C), except in tricky code meant to test undergrads' understanding of the ^ operator. (In assembly, there may be speed advantages on some architectures.)
It it's the exclusive or operator. It will do bitwise exclusive or on the two arguments. If the numbers are equal, this will result in 0, while if they're not equal, the bits that differed between the two arguments will be set.
You generally wouldn't use it inserted of ==, you would use it only when you need to know which bits are different.
Two real usage examples from an embedded system I worked on:
In a status message generating function, where one of the words was supposed to be a passthrough of an external device's status word. There was an disconnect between the device behavior and the message spec - one thought bit0 meant 'error' while the other thought it meant 'OK'.
statuswords[3] = devicestatus ^ 1; //invert B0
The 16-bit target processor was terribly slow to branch, so in an inner loop if (sign(A)!=sign(B) B=0; was coded as:
B*=~(A^B)>>15;
which took 4 cycles rather than 8, and does the same thing: sets B to 0 iff the sign bits are different.
in many general cases we might use '^' as a replacement for'==' but that doesn't exactly give the result for being equal or not.Instead - it checks the given variables bit by bit and sets a result for each bit individually and finally displays a result summed up with the resulting bits as a bulk.
So I see that this question has already been asked, however the answers were a little vague and unhelpful. Okay, I need to implement a c expression using only "& ^ ~ ! + | >> <<"
The expression needs to resemble: a ? b : c
So, from what I've been able to tell, the expression needs to look something like:
return (a & b) | (~a & c)
This works when a = 0, because anding it with b will give zero, and then the or expression will return the right side, (~a & c) which works because ~0 gives all ones, and anding c with all ones returns c.
However, this doesn't work when a > 0. Can someone try to explain why this is, or how to fix it?
I would convert a to a boolean using !!a, to get 0 or 1. x = !!a.
Then I'd negate that in two's complement. Since you don't have unary minus available, you use the definition of 2's complement negation: invert the bits, then add one: y = ~x + 1. That will give either all bits clear, or all bits set.
Then I'd and that directly with one variable y & b, its inverse with the other: ~y & c. That will give a 0 for one of the expressions, and the original variable for the other. When we or those together, the zero will have no effect, so we'll get the original variable, unchanged.
In other words, you need a to have all bits set to 0, if a is false (i.e. 0), and have all bits set to 1, if a is true (i.e. a > 0).
For the former case, the work is already done for you; for the latter -- try to work out result of the expression ~!1.
So the problem is to add 3 numbers together(2's complement) in C. Normally should be very simple, but the hard part of this problem is that you can only use the ops ! ~ & ^ | << >>, no kind of loops, or function calls, or anything fancy. Just those ops. He gives us a function that adds 2 words together. The return of the function I'm writing (sum3) is return sum(word1, word2). My responsibility is to determine what to set word1 and word2 to in order for the call to the sum function to give me the proper answer. Oh, and also I can only use 16 total of those ops up there.
I tried setting word1 to x ^ y, and word2 to (x & y) << 1 to see if I at least got the right answer from that for the first 2 numbers, and it always ends up correct. However, I have no idea how to throw z into the mix without messing everything up. I think this is is the biggest problem...somebody please help, I messed up and didn't realize this was due in 5 hours from now, so I'm freaking out. At least a good hint...something, anything.
Just a hint: a + b == (a ^ b) + ((a & b) << 1). Here a & b is the expression for carry.
As you can see, by this transformation you reduce an add on N bits to some logical operations and an add on N-1 bits. If the N is given, you could manually unroll the loop and the whole result will contain only XOR, AND and SHL(1).