Can anyone help me in understanding the following code:-
int r, countIt(int n) {
while (r += " 2 "[n % 10] & 3, n /= 10);
return r;
}
I found this code in one of the challenges of codefights.com, https://codefights.com/challenge/v5Zg8trjoun3PTxrZ/solutions/Aj3ppbhSShixt4nBi
This is a solution for counting number of holes in a number.
e.g.
1111 = 0
0000 = 4
1234 = 0
8888 = 8
I am not able to understand the following things:
1. Logic of this code
2. comma (,) operator used in return data type of the function
3. Use of []operator after string.
4. And actually the whole code.
Is that some kind of obfuscated C contest submission? Or code golf?
First, the weird declaration. It's just combining two unrelated declarations on one line. Just as
int x, y;
is equivalent to
int x;
int y;
so is your code equivalent to
int r;
int countIt(int n) {...}
It's a little known and, thankfully, little used quirk of the C grammar that you can do that.
The loop would become clearer if written this way:
do {
r += " 2 "[n % 10] & 3;
n /= 10;
} while (n);
It basically iterates over digits in the decimal representation of n
.
Now the part of r += " 2 "[n % 10] & 3;
. n % 10
is the low-order decimal digit of n
. We use that as an index into a string literal (which is just an array of char
s), then extract two low-order bits of the character's ASCII code and discard the rest. I'm pretty sure that, in the original program you copied this code from, the characters in that literal were not spaces, but rather certain unprintable characters chosen in such a way that the two low-order bits of their ASCII codes gave precisely the number of "holes" in the corresponding digit. 2
character is a red-herring - it's in position 12, but only characters 0 through 9 are actually used.
In other words, this part can be more clearly written this way:
static const int numHoles[10] = {1, 0, 0, 0, 1, 0, 1, 0, 2, 1};
int digit = n % 10;
r += numHoles[digit];
Put together, we have:
int countIt(int n) {
// number of holes in digit 0 1 2 3 4 5 6 7 8 9
static const int numHoles[10] = {1, 0, 0, 0, 1, 0, 1, 0, 2, 1};
int r = 0;
do {
int digit = n % 10;
r += numHoles[digit];
n /= 10;
} while (n);
return r;
};
I looked up the link you provided. After carefully observing the code i came to following conclusion.
int r, countIt(int n) {.....}
is equivalent to writing as
int r;
int countIt(int n){.....}
now for
while (r += " 2 "[n % 10] & 3, n /= 10);
is equivalent to:
do{
r += " 2 "[n % 10] & 3;
n/=10;
}while(n);
Now comes the logical part of the code
r += " 2 "[n % 10] & 3;
let me give you some basics.
cout<<"abcde"[2];
will give you output
c
now if you watch carefully the code in link which you provided its something like this:
r += " 2 "[n % 10] & 3;
is nothing but
r += "TAB,SPACE,SPACE,SPACE,SPACE,SPACE,TAB,SPACE,2,TAB"[n % 10] & 3;
Now its time to explain how this code is calculating number of holes. The ASCII value of TAB is 9 whose binary equivalent is 1001. The ASCII value of SPACE is 32 whose binary equivalent is 100000.
so bit wise anding TAB with 3 will result
1001 & 0011 = 0001 which is 1
bit wise anding SPACE with 3 will result
100000 & 000011 = 000000 which is 0
replacing TABs with 1 and SPACEs with 0 hence this concludes as writing
do{
r += "1000001021"[n % 10] & 3;
n/=10;
}while(n);
n % 10 is the low-order decimal digit of n. We use that as an index into a string literal, which contains information about how many holes is there in that low-order decimal digit then add it to result r.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With