Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't understand this code?

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.

like image 319
Rishabh Gupta Avatar asked Dec 19 '22 10:12

Rishabh Gupta


2 Answers

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 chars), 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;
};
like image 103
Igor Tandetnik Avatar answered Dec 24 '22 01:12

Igor Tandetnik


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.

  1. In c++

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.

like image 39
BlessonThomas Avatar answered Dec 24 '22 00:12

BlessonThomas