JPEG category encode bitwise operation - c

In the Cryx note about JPEG compression, categories are described as "the minimum size in bits in which we can keep that value". It goes on to say that values falling within certain ranges are put into categories. I have pasted a segment below but not the whole table.
Values Category Bits for the value
0 0 -
-1,1 1 0,1
-3,-2,2,3 2 00,01,10,11
-7,-6,-5,-4,4,5,6,7 3 000,001,010,011,100,101,110,111
The JPEG encoder/decoder found here performs the category encoding with a bitwise operation that I don't understand and I am hoping someone can clarify for me. RLE of 0's is done elsewhere, but this portion of the code breaks up the remaining pixel values into the categories as specified in the Cryx document.
In the code below, the variable code is the value of the YUV value of the pixel. In the while loop, if the conditions are met, i is decremented until the correct category is reached. For example, if the pixel value is 6.0, starting from category 15, i is decremented until 3 is reached. This is done with a bitwise operation that I do not understand. Can someone please clarify what condition is being tested for in the while loop? More specifically, !(absc & mask) is a Boolean, but I don't understand how this helps us to know the correct category.
The reason for the last if statement is also unclear to me. Thanks
unsigned absc = abs(*code);
unsigned mask = (1 << 15);
int i = 15;
if (absc == 0) { *size = 0; return; }
while (i && !(absc & mask)) { mask >>= 1; i--; }
*size = i + 1;
if (*code < 0) *code = (1 << *size) - absc - 1;

while here is used to find the most significant bit in code. Or in other words - length of code in bits.
The loop consequently applies mask to get next bit in code. First, mask is 1000000000000000 in binary form with 1 in 15th bit (zero based), the most valued bit in 2-byte (16 bit) number. Operator & (binary AND) zeros all bits in absc except one with 1 in mask. If result is zero than shift mask right (remove last binary digit) and repeat with next bit.
For value 6 = 110b (binary form) while will work till mask = 100b and i = 2. After it size will be set to 3.
If code was negative than the last line will convert it in one’s compliment representation with size length. Such encoding of negative numbers is described in your categories list.

Related

UNDERSTANDING how to count trailing zeros for a number using bitwise operators in C

Note - This is NOT a duplicate of this question - Count the consecutive zero bits (trailing) on the right in parallel: an explanation? . The linked question has a different context, it only asks the purpose of signed() being use. DO NOT mark this question as duplicate.
I've been finding a way to acquire the number of trailing zeros in a number. I found a bit twiddling Stanford University Write up HERE here that gives the following explanation.
unsigned int v; // 32-bit word input to count zero bits on right
unsigned int c = 32; // c will be the number of zero bits on the right
v &= -signed(v);
if (v) c--;
if (v & 0x0000FFFF) c -= 16;
if (v & 0x00FF00FF) c -= 8;
if (v & 0x0F0F0F0F) c -= 4;
if (v & 0x33333333) c -= 2;
if (v & 0x55555555) c -= 1;
Why does this end up working ? I have an understanding of how Hex numbers are represented as binary and bitwise operators, but I am unable to figure out the intuition behind this working ? What is the working mechanism ?
The code is broken (undefined behavior is present). Here is a fixed version which is also slightly easier to understand (and probably faster):
uint32_t v; // 32-bit word input to count zero bits on right
unsigned c; // c will be the number of zero bits on the right
if (v) {
v &= -v; // keep rightmost set bit (the one that determines the answer) clear all others
c = 0;
if (v & 0xAAAAAAAAu) c |= 1; // binary 10..1010
if (v & 0xCCCCCCCCu) c |= 2; // binary 1100..11001100
if (v & 0xF0F0F0F0u) c |= 4;
if (v & 0xFF00FF00u) c |= 8;
if (v & 0xFFFF0000u) c |= 16;
}
else c = 32;
Once we know only one bit is set, we determine one bit of the result at a time, by simultaneously testing all bits where the result is odd, then all bits where the result has the 2's-place set, etc.
The original code worked in reverse, starting with all bits of the result set (after the if (c) c--;) and then determining which needed to be zero and clearing them.
Since we are learning one bit of the output at a time, I think it's more clear to build the output using bit operations not arithmetic.
This code (from the net) is mostly C, although v &= -signed(v); isn't correct C. The intent is for it to behave as v &= ~v + 1;
First, if v is zero, then it remains zero after the & operation, and all of the if statements are skipped, so you get 32.
Otherwise, the & operation (when corrected) clears all bits to the left of the rightmost 1, so at that point v contains a single 1 bit. Then c is decremented to 31, i.e. all 1 bits within the possible result range.
The if statements then determine its numeric position one bit at a time (one bit of the position number, not of v), clearing the bits that should be 0.
The code first transforms v is such a way that is is entirely null, except the left most one that remains. Then, it determines the position of this first one.
First let's see how we suppress all ones but the left most one.
Assume that k is the position of the left most one in v. v=(vn-1,vn-2,..vk+1,1,0,..0).
-v is the number that added to v will give 0 (actually it gives 2^n, but bit 2^n is ignored if we only keep the n less significant bits).
What must the value of bits in -v so that v+-v=0?
obviously bits k-1..0 of -k must be at 0 so that added to the trailing zeros in v they give a zero.
bit k must be at 1. Added to the one in vk, it will give a zero and a carry at one at order k+1
bit k+1 of -v will be added to vk+1 and to the carry generated at step k. It must be the logical complement of vk+1. So whatever the value of vk+1, we will have 1+0+1 if vk+1=0 (or 1+1+0 if vk+1=1) and result will be 0 at order k+1 with a carry generated at order k+2.
This is similar for bits n-1..k+2 and they must all be the logical complement of the corresponding bit in v.
Hence, we get the well-known result that to get -v, one must
leave unchanged all trailing zeros of v
leave unchanged the left most one of v
complement all the other bits.
If we compute v&-v, we have
v vn-1 vn-2 ... vk+1 1 0 0 ... 0
-v & ~vn-1 ~vn-2 ... ~vk+1 1 0 0 ... 0
v&-v 0 0 ... 0 1 0 0 ... 0
So v&-v only keeps the left most one in v.
To find the location of first one, look at the code:
if (v) c--; // no 1 in result? -> 32 trailing zeros.
// Otherwise it will be in range c..0=31..0
if (v & 0x0000FFFF) c -= 16; // If there is a one in left most part of v the range
// of possible values for the location of this one
// will be 15..0.
// Otherwise, range must 31..16
// remaining range is c..c-15
if (v & 0x00FF00FF) c -= 8; // if there is one in either byte 0 (c=15) or byte 2 (c=31),
// the one is in the lower part of range.
// So we must substract 8 to boundaries of range.
// Other wise, the one is in the upper part.
// Possible range of positions of v is now c..c-7
if (v & 0x0F0F0F0F) c -= 4; // do the same for the other bits.
if (v & 0x33333333) c -= 2;
if (v & 0x55555555) c -= 1;

C program to find required number of bits for a given number [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I am new at programming and trying to understand the following program.
This program gets the minimum number of bits needed to store an integer as a number.
#include <stdio.h>
/*function declaration
* name : countBit
* Desc : to get bits to store an int number
* Parameter : int
* return : int
*/
int countBit(int);
int main()
{
int num;
printf("Enter an integer number :");
scanf("%d",&num);
printf("Total number of bits required = %d\n",countBit(num));
return 0;
}
int countBit(int n)
{
int count=0,i;
if(n==0) return 0;
for(i=0; i< 32; i++)
{
if( (1 << i) & n)
count=i;
}
return ++count;
}
Can you please explain how the if( (1 << i) & n) condition works?
To begin you should read up on Bitwise Operators.
for(i=0; i< 32; i++)
{
// Check if the bit at position i is set to 1
if( (1 << i) & n)
count=i;
}
In plain english, this is checking what the highest position of all "set" bits is.
This program gets the minimum number of bits needed to store an integer as a number.
Getting the position of the largest "set" bit will tell us how many bits we need to store that number. If we used a lesser amount of bits, then we would be reducing our maximum possible number to below our desired integer.
"<<" and "&" are bitwise operators, that manipulate a given (usually unsigned integer) variable's bits. You can read more about such operators here. In your case,
1<<i
is the number whose binary representation is 1 followed by i-1 zeroes (and preceded only by zeroes as well). Overall, the check
(1<<i)&n
evaluates to true if the i-th bit of the variable n is 1, and false otherwise, and therefore the loop finds out what is the leftmost bit which is 1 in the given number.
Its very simple if you understand bitwise operators.
Shift operator: <<is a left shift operator, which shifts a value by designated bits. In C, x << 1, will shift x by 1-bit.
Lets just consider 8-bit values for now and lets say x is 100 in decimal, 0x64 in Hexadecimal numbering system and binary representation of the same would be 0110 0100
Using the shift operator, lets shift this value 1-bit. So,
0 1 1 0 0 1 0 0
becomes
0 1 1 0 0 1 0 0 0
^ ^
Discarded Padded
as the last (right extreme) bit will be padded with a 0.
The number becomes, 0xC8, which is 200 in decimal numbering system, which is double the previous value!
The same goes for a >> operator, try it yourselves if you haven't. Result should be the half, except for when you try to 0x01 :-)
As a side note, when you'll grow up and start looking at the way shell/console is used by developers, you'll understand that > has a different purpose.
The & operator: Firstly, && and & is different. First one is a logical operator and the latter one is a bitwise operator.
Lets pick a number again, 100.
In logical and operation, the end result is always true or false. For example, 0x64 && 0x64 will result in a true condition, all other combinations will result in a false result.
But, the bitwise and operation, is used this way: Is the ith bit of 0x64 set? If yes, results in true, else results in false.
The if statement:
if( (1 << i) & n)
is doing just that. For every iteration of loop, it left shifts 1 by i bits, and then checks if the ith bit of n is set, results in true if set, else results in false.
Programmers usually use a macro for this, which makes it more readable.
#define CHECK_BIT(value, position) ((value) & (1 << position))

bit comparison in loop on AVRs

I'm learning about bit logic in C on AVRs and I have a problem.
I want to compare an "i" bit (from the right) from int8_t variable and if it is 1, then do the next instruction, but it doesn't work. Here's what I write:
if (variable & (1<<i)==(1<<i)) instruction;
In example for following data:
uint8_t dot=0101;
PORTC=1;
for (int i=0; i<4; i++)
{
PORTB = fourDigit[i];
if (dot & (1<<i)==(1<<i)) PORTB--;
PORTC<<=1;
}
The dot (as it is connected to PB0) should illuminate on the first and third digit, but at present it lamps on every digit. What's the problem?
Thanks for your time.
It is done by bit masking. If you want to check whether or not an i'th bit of a is 1 you will do something like this:
if (a & (1 << i))
{
// Do something
}
This way all of the bits of a except the i'th one will be ANDed with zeros, thus getting a value of zero. The i'th bit will be ANDed with 1, thus not changing it's value. So the if condition will be true in case the bit is not zero, and false otherwise.
The comparison code you are presenting should work as well, but I suspect the dot variable is not containing the value you think it is containing. uint8_t dot=0101; makes it to be equal to 101 in octal base (due to the leading zero) or 65 in decimal. Not 101 in binary.

Finding next bigger number with same number of set bits

I'm working on a problem where I'm given a number n, I have to find the next larger element with same number of set bits. While searching on Internet, I found an interesting piece of code which does this in few lines of code (BIT MAGIC) here:
unsigned nexthi_same_count_ones(unsigned a) {
/* works for any word length */
unsigned c = (a & -a);
unsigned r = a+c;
return (((r ^ a) >> 2) / c) | r);
}
But I want to understand the underlying logic about the algorithm that it will work always. All the boundary cases will be handled properly.
Can someone please explain the logic in simple steps.
Thanks
In the next higher number, the leftmost 1 of the rightmost run of 1s exchanges place with the 0 to its left, while the remaining 1s move to the far right.
The code isolates lowest 1,
adds it to a (making carries ripple through to the next higher 0, inverting all those bits)
The ex-or gets the least significant run of ones, extended one position to the left.
Shifting it right two positions takes its left boundary one position right of the original one
(leaving place for that one 0 from the high position),
dividing by the lowest 1 makes room for as many 0-bits more as there were on the right end of a.
Let say we have a bit pattern such as
111100111 - representing 487 in decimal
to generate the next highest integer whilst preserving the number of 0's and 1's as in the input we need to find the first 0 bit from the right of the input that is followed by 1, and we need to toggle this bit to a 1. We then need to reduce the number of 1's on the right of this flip point by 1 to compensate for the bit we switched from a 0 to 1.
our new bit pattern will become
111101011 - 491 in decimal (we have preserved the no of bits set and not set as per the input)
int getNextNumber(int input)
{
int flipPosition=0;
int trailingZeros=0;
int trailingOnes=0;
int copy = input;
//count trailing zeros
while(copy != 0 && (copy&1) == 0 )
{
++trailingZeros;
//test next bit
copy = copy >> 1;
}
//count trailing ones
while(copy != 0 && (copy&1) == 1 )
{
++trailingOnes;
//test next bit
copy = copy >> 1;
}
//if we have no 1's we cannot form another patter with the same number of 1's
//which will increment the input, or if we have leading consecutive
//zero's followed by consecutive 1's up to the maximum bit size of a int
//we cannot increase the input whilst preserving the no of 0's and
//1's in the original bit pattern
if(trailingZeros + trailingOnes == 0 || trailingZeros + trailingOnes == 31)
return -1;
//flip first 0 followed by a 1 found from the right of the bit pattern
flipPosition = trailingZeros + trailingOnes+1;
input |= 1<<(trailingZeros+trailingOnes);
//clear fields to the right of the flip position
int mask = ~0 << (trailingZeros+trailingOnes);
input &= mask;
//insert a bit pattern to the right of the flop position that will contain
//one less 1 to compensate for the bit we switched from 0 to 1
int insert = flipPosition-1;
input |= insert;
return input;
}

How does this method count the number of 1s in binary representation? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
n & (n-1) what does this expression do?
Consider the following algorithm:
int count(int num)
{
int ones = 0;
while(num)
{
++ones;
num &= num - 1;
}
return ones;
}
What is the significance of num & (num-1)? How does it work?
num &= num - 1;
clears the least significant bit set in num.
This algorithm counts the bits set by clearing them and incrementing a counter until they're all gone.
To understand why it clears the least significant bit, you need to think about what decrementing does to the bits and of course understand what the & operation does.
Subtracting in binary works just as the process we were all taught in decimal as children.
You work from right (least significant) to left, simply subtracting individual digits when possible, and "borrowing" from the next digit when necessary.
When subtracting 1 from a binary number ending in a set of zeros, this "borrowing" and subtracting turns all the zeros in lower positions than the rightmost 1 to 1's and turns the rightmost 1 to a zero (because it was borrowed).
Then applying the & operator leaves all the lesser digits zero because they're zero in num, and sets the least significant bit of num to zero because it's zero in num-1.
Both of these operations leave the more significant digits unchanged.
Here's a good list of bit twiddling hacks including this one, which is due to Brian Kernighan.
Here's a more detailed (but not very well written!) answer.
There are two cases: either the least significant bit is set, then "num-1" unsets it. Or it's not set, then num-1 turns all trailing zeroes into 1, and the least significant 1 to a 0, the rest of the bits are not changed. When you "and", all unchanged bits are the same, the least significant 1 which is anded with a 0 turns into a 0 and the others remaining bits are zeroes. This is illustrated here:
num = 1000110111[1]0000
num - 1 = 1000110111[0]1111
num & (num - 1) = 1000110111[0]0000
I would point out that there is often an assembly operation to count the number of ones in a single cycle. The operation is called "popcount" and for instance in GCC, it can be accessed using "__builtin_popcount", see this link for details.
The algorithm operates like pump, moving bits effectively to right in the "num" variable. The line
num &= num - 1;
is where the work is done, there's an assignment and boolean AND operation going on at the same time. It's all about bit arithmetic.
Pom

Resources