3

I want to use 128-bit unsigned integer in C. I have written the following code:

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<math.h>
#include <stdint.h>
#include <limits.h>

#define unt __uint128_t
#define G1 226854911280625642308916404954512140970


int countSetBits(unt n){
    int count = 0;
    while(n){ n &= (n-1) ; count++; }
        return count;
}
int main(){


        printf(" %d\n",countSetBits(G1) );

}

Although output should be 64, number of bits of G1, it is coming 96. I use gcc compiler. I know GMP GNU, but for my purpose, I need fast execution. Hence I want to avoid GNU library.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
user12290
  • 621
  • 1
  • 5
  • 13
  • I would suggest writing your own library and working on two `uint64_t` values. – KamilCuk Sep 15 '18 at 19:29
  • Possible duplicate of [Assigning 128 bit integer in C](https://stackoverflow.com/questions/31461318/assigning-128-bit-integer-in-c) – KamilCuk Sep 15 '18 at 19:29
  • 6
    For those who can't convert 226854911280625642308916404954512140970 into hex mentally, the `bc` command says the value is 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA (which is 32 nybbles with hex value A). – Jonathan Leffler Sep 15 '18 at 19:31
  • For my purpose, other operations are working perfectly like xor etc. Is it possible to convert __uint128_t into two uint64_t numbers in countSetbit function? – user12290 Sep 15 '18 at 19:37
  • @user12290 Do you want to check number of set bits or total number of bits? – kiran Biradar Sep 15 '18 at 19:51
  • I want to check the number of 1's of some random 128 bits integers. – user12290 Sep 15 '18 at 19:55

3 Answers3

3

Because of an issue explained here, you need to assign the constant using two 64 bit values:

#include <stdio.h>

#define uint128_t __uint128_t
#define G1  ((uint128_t)12297829382473034410 << 64 | (uint128_t)12297829382473034410)


int countSetBits(uint128_t n) {
    int count = 0;
    while(n) {
        n &= (n - 1); 
        count++;
    }
    return count;
}
int main() {
    printf(" %d\n",countSetBits(G1) );
}

Outputs:

 64

Live version available in onlinegdb.

KamilCuk
  • 120,984
  • 8
  • 59
  • 111
  • Thank you. But here G1 is an example. In my case, some 128 bit random numbers are generated. I want to count their number of bits. – user12290 Sep 15 '18 at 19:45
  • You can `rand()`. `static_assert(RAND_MAX = 1<<32-1, '"); (uint128_t)rand()<<(64*3) | (uint128_t)rand()<<(64*2) | (uint128_t)rand()<<(64*1) | (uint128_t)rand()<<(64*0)`. Or use `lrand48()`. You have a pure 128 bit number random generator? That 128 bit must be constructed from lower-bit calls... And still the best is to create a small 128-bit library using 2 uint64_t bit numbers and static inlines. Such way is the best portable think you can do. – KamilCuk Sep 15 '18 at 20:55
  • `12297829382473034410` is problem as it is an out of range 64-bit signed constant. Recommend `(uint128_t)12297829382473034410u` (add `u`) – chux - Reinstate Monica Sep 15 '18 at 21:09
3

Since you're using one gcc extension, I assume more are okay. gcc has a family of intrinsic functions for returning the number of set bits in regular integer types. Depending on your CPU and gcc options, this will either become the appropriate instruction, or fall back to calling a library function.

Something like:

int bitcount_u128(unsigned __int128 n) {
  uint64_t parts[2];
  memcpy(parts, &n, sizeof n);
  return __builtin_popcountll(parts[0]) + __builtin_popcountll(parts[1]);
}

If using an x86 processor with the popcnt instruction (Which is most made in the last decade), compile with -mpopcnt or the appropriate -march= setting to use the hardware instruction.

Alternatively, if you're okay with limiting support to just x86 processors with popcnt, the _mm_popcnt_u64() intrinsic from <nmmintrin.h> can be used instead of __builtin_popcountll().

Shawn
  • 47,241
  • 3
  • 26
  • 60
2

There are no 128 constants in C language so you need to use two 64 bit values and combine them

#define unt __uint128_t
#define G1 ((((__uint128_t)0xaaaaaaaaaaaaaaaaull) << 64) + ((__uint128_t)0xaaaaaaaaaaaaaaaaull))


int countSetBits(unt n){
    int count = 0;
    while(n){ n &= (n-1) ; count++; }
        return count;
}

int countSetBits1(unt n){
    int count = 0;
    while(n) 
    {
        count += n & 1;
        n >>= 1;
    }
        return count;
}


int main(){


        printf(" %d\n",countSetBits(G1) );
        printf(" %d\n",countSetBits1(G1) );

}
0___________
  • 60,014
  • 4
  • 34
  • 74
  • Note that the `ll` in `0xaaaaaaaaaaaaaaaaull` is not needed, nor is the 2nd `(__uint128_t)` cast. – chux - Reinstate Monica Sep 15 '18 at 21:06
  • @chux I prefer to add instead of debugging. Keyboards are cheap and easy replaceable and cast or `ull` does not make any harm but very often can avoid silly errors and hours of frustration. – 0___________ Sep 16 '18 at 00:54