1

Assume that you have an array of uint8_t in C with the size of the array to be 10. I want to generate all possible binary combinations with these 80 bits, inside the array.

This could be implemented with 10 nested loops one for every element of the array. However, when you don't know the size then you cannot dynamically change the number of nested loops.

Is there any recursive method so that you can consider this 80 bit as a single number and count from 000000000..... up to 1111111111.... where the number of zeros and ones are equal to 80?

I considered the GNU gmp but the largest number is 1024 bits and you cannot access them as simple bits that represent actual numbers.

All I want to make is a big counter, that counts from 0 up to 2^80 but inside the array.

I want to give an example. Array of uint8_t with two bytes:

|00000000|00000000|

|00000000|00000001|

|00000000|00000010| . . .

|00000000|11111111|

|00000001|00000000|

|00000001|00000001|

|00000001|00000010|

. .

#include <gmp.h>
#include <stdio.h>
#include <assert.h>


int main()
{

  mpz_t n;

  int flag;

  //Initialize the number.

  mpz_init(n);

  mpz_set_ui(n,0);


 //Add one to the number */

  mpz_add_ui(n,n,1); /* n = n + 1 */

}

How would you access the number n and copy the contents to your array?

memcpy(array, &n, 10) ?
15
  • I understand that it might never finish. But if the array was of fewer bytes then it could finish. Commented Jul 10, 2016 at 13:19
  • 1
    @2501 or you need to simply correctly use GMP, whose whole purpose is allowing of efficient handling of such operations. Commented Jul 10, 2016 at 13:41
  • 1
    @MarcusMüller OP is practicing. Using GMP defeats this intention. Commented Jul 10, 2016 at 13:44
  • 1
    @2501: I agree. This is a nice lesson in learning how to use a carry. I do think that 10 bytes are a bit too long, since it will take ages. I would first try with 4 bytes. The principle is the same. Commented Jul 10, 2016 at 13:47
  • 2
    @J.East. You're still going to have to show your attempt and ask a specific question. I hope you're not expecting that someone will write the code for you. Commented Jul 10, 2016 at 13:51

6 Answers 6

2

You can use something like the code below.

But keep in mind that it's not so efficient. If you want better performance, use an array of unsigned long longs.

Alternative solution would be to use an existing library like GMP.

#include <stdio.h>
#include <stdint.h>

#define SZ 10
int main(void)
{
    uint8_t arr[SZ];
    for (int i = 0; i < SZ; i++)
        arr[i] = 0;

    for (int i = 0; i < SZ*2; i++)
        putchar('0');
    putchar('\n');

    while (1)
    {
        for (int i = 0; i <= SZ; i++)
        {
            if (i == SZ)
                goto stop;
            arr[i]++;
            if (arr[i] != 0xff)
                break;
        }

        const char *digits = "0123456789abcdef";
        for (int i = SZ-1; i >= 0; i--)
        {
            putchar(digits[(arr[i] >> 4) & 0xf]);
            putchar(digits[arr[i] & 0xf]);
        }
        putchar('\n');
    }
  stop:
    puts("Done! Wow, you're still alive?");
}
Sign up to request clarification or add additional context in comments.

3 Comments

don't re-invent the wheel. GMP does this, but better, and OP already knows GMP.
@MarcusMüller Thanks, I've added the info about GMP to the answer. While it is reinventing the wheel, I'm sure that OP does it for pratice, which is ok.
Thanks, I think this is helpful for future readers! (Albeit OP originally, looking into the edit history, claimed that this was impossible with GMP, which is a misconception, so I don't think he's practicing)
2

What you want to do is impossible, at least in this universe.

All 80-bit combinations is identical to all numbers up to 2⁸⁰ – that's a very large number.

As you've already noticed, each of these values will have a memory demand of 10B – amounting to a total of

10 B * 2⁸⁰ = 12089258196146291747061760 B
           = 10 B * 2⁵⁰Gi
           = 10 * 2⁴⁰ TiB

or in other words, this is about 5.5 Trillion SSDs of a capacity of 2 Terabyte each.

Let each SSD weigh about 80g, then this amounts to a mass of 439,804,651 tonnes.

Because you're a bit stubborn: Even if you're not storing this in RAM or on disk, there's no chance this will ever complete: Here's a graph of your "binary combinations in N bytes array" problem. Notice that the y axis has the unit 10^28.

Number of Operations vs Array length

and because that is not really helpful as is, with a logarithmic y axis:

logarithmic scale

Assuming your PC can go through a whole billion of these arrays per second, this is the amount of time it'll take:

Years wasted on generating the arrays

So, for a seven byte array, just generating the arrays and immediately discarding them will take more than two years. Your 10 B array would need roughly 38 million years of CPU time. Good luck!

Anyway, recursion is the worst algorithmic choice, you can just take a for loop and count up. There's no ambiguity here, and this will work perfectly with GMP. I don't know what you're doing wrong. Learn to use GMP:

mpz_t number, limit;

mpz_init_set_ui(number, 0UL); //first value
mpz_init_set_ui(limit, 2UL); // limit=2
mpz_pow_ui (limit,limit,80); // limit=2**80

while(mpz_cmp(number,limit) < 0) { // while number smaller limit
     mpz_out_str(stdout, 2, number);
     mpz_add_ui(number, number, 1UL); //increase number
}

number now takes all possible 2^80 values, and those are printed in binary. In theory.

11 Comments

I don't want to store them. I am talking about an array of 80 bits, that you flip bits from 0000.... up to 11111..... There is nothing to store other than this 80 bits.
yes, but really? you'll not see any of this nearly complete within your lifetime. Not even closely.
I did not ask you if I am stubborn or not. I did not ask you if it needs trillion of years. I asked how it could be done. Thank you for the nice graphs I might have available the Chinese super computer...
@MarcusMüller: it can't be done in time, but it can be shown how it could be done. It would have made more sense with a smaller array, but the principle is exactly the same.
@LukeVanIn OP: "I want to generate all possible binary combinations with these 80 bits, inside the array." <- I think we need to generate all of them :/
|
1

This is unchecked, unoptimized code that with a bit of luck may do what you want.

void add(uint8_t* in1,
        uint8_t* in2,
        uint8_t* out,
        size_t length)

{
  uint8_t carry = 0;
  for (size_t i = 0;
       i < length;
       ++i)
  {
    uint16_t res = in1[i] + in2[i] + carry;
    out[i] = (uint8_t)(res & 0xff);
    carry = res >> 8;
  }
}

Comments

1

A quick and dirty C solution :

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>

typedef
struct {
  size_t size;
  uint8_t data[];
} bignum_t;

bignum_t *bn_new(size_t size)
{
  // assert size>0
  bignum_t *new=malloc(sizeof *new + sizeof(uint8_t[size]));
  if (new==NULL) {
    perror("malloc");
    exit(EXIT_FAILURE);
  }
  new->size=size;
  memset(new->data,0,size);
  return new;
}

void bn_free(bignum_t *bn)
{
  free(bn);
}

bool bn_next(bignum_t *bn)
{
  size_t i;
  for(i=0; i<bn->size; ++i)
    if (bn->data[i]==0xFF)
      bn->data[i]=0;
    else
      break;

  if (i==bn->size) return false;
  bn->data[i]++;
  return true;
}

void bn_print(bignum_t *bn)
{
  putchar('[');
  for(size_t i=0; i<bn->size; ++i)
    printf(" %02X", bn->data[i]);
  printf(" ]");
}

int main(void)
{
  bignum_t *bn=bn_new(10);

  do {
    bn_print(bn);
    putchar('\n');
  } while (bn_next(bn));

  bn_free(bn);

  return 0;
}

Don't expect to see the end of this program.

Comments

1

This is very doable. You will need:

  1. An array to store the bytes.
  2. A way to increment a byte.
  3. A way to carry the overflow when the range of the byte is exceeded.

This can all be done in one function. In the worst case the stack only needs to recurse as deep as the number of bytes (10 bytes = 10 stack recursions).

Here's one I prepared earlier. It supports an arbitrary number of bytes, although it only uses three bytes to give yourself a chance to see it run to the end.

#include <stdio.h>
#include <math.h>
#include <stdint.h>

void increment(uint8_t * bytes, int size, int i) {

    if (i >= size) {
        // Number overflow, start at 0.
        return;
    }

    uint8_t b = bytes[i];

    // Check if byte will overflow.
    if (b == 0xFF) {
        // Byte overflow, carry overflow to next byte.
        b = 0;
        increment(bytes, size, i + 1);
    }
    else {
        // Increment byte.
        b ++;
    }

    bytes[i] = b;
}

int equal(const uint8_t * a, const uint8_t * b, int size) {

    for (int i = 0; i < size; i++) {
        if (a[i] != b[i]) {
            // At least one byte is different.
            return 0;
        }
    }

    // All bytes are the same.
    return 1;
}

void printBytes(const uint8_t * bytes, int size) {

    for (int i = 0; i < size; i++) {
        printf("%02x ", bytes[size - i - 1]);
    }

    printf("\n");
}

int main(int argc, const char * argv[]) {

    // Add more bytes here: { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
    uint8_t bytes[] = { 0, 0, 0 };
    uint8_t max[] = { 0xFF, 0xFF, 0xFF };
    int size = sizeof(bytes);

    while (!equal(bytes, max, size)) {

        printBytes(bytes, size);

        increment(bytes, size, 0);
    }

    return 0;
}

8 Comments

I think that &bytes is not needed. The name of the array is already an address, so you need simple bytes without &.
Doh! Such a noob mistake! Well spotted.
Why it goes from 00000000 00000000 0000007f to 00000000 00000000 ffffff80 ?
Er ... I'm having an off day. There was a bug in the if statement which checked the overflow. Fixed now. Also fixed the print statement - it was printing out a full 32 bit int for each byte. Since it's hex, it only needs two characters per byte.
Nice! I am sorry for this. One last addition is #include <stdint.h>. Works fine now!
|
0

this is a simple c solution to the problem, printing the binary equivalent of each number.

although a few solutions have already been presented, mine is one that prints binary and it is recursive.

#include <stdio.h>
#include <stdint.h>

void Print(uint8_t *, int);
void IncrementLoop(uint8_t *arr, int sz);
int GetBit(uint8_t *arr, int idx);

int main()
{
    uint8_t ca[2] = {0xFF, 0};

    IncrementLoop((uint8_t *)ca, 16);

    return 0;
}


void IncrementLoop(uint8_t *arr, int sz)
{
    int number_of_bytes = sz / 8;
    int count = 0;

    while((*arr) == (uint8_t)0xFF)
    {
        ++arr;
        ++count;
        if(count >= number_of_bytes)
        {
            return;
        }
    }

    (*arr) += 1;
    for(;count;--count)
    {
        --arr;
        (*arr) &= 0;
    }
    Print(arr, sz);
    IncrementLoop(arr, sz);
}

void Print(uint8_t *arr, int sz)
{

    while(sz)
    {
        printf("%d", GetBit(arr,sz-1));
        --sz;
    }

    printf("\n");
}

int GetBit(uint8_t *arr, int idx)
{
    return (1 & (arr[(idx/8)] >> (idx % 8)));
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.