使用C中任意大小的uint8_t数组生成所有可能的二进制组合

时间:2016-07-10 13:08:55

标签: c recursion

假设C中有一个uint8_t数组,数组大小为10.我想在数组中生成所有可能的二十进制组合。

这可以用10个嵌套循环实现,每个元素对应一个元素。但是,当您不知道大小时,则无法动态更改嵌套循环的数量。

是否有任何递归方法,以便您可以将此80位视为单个数字并从000000000 .....计数到1111111111 ....其中0和1的数量等于80?

我考虑过GNU gmp,但最大的数字是1024位,你不能将它们作为代表实际数字的简单位来访问。

我想做的只是一个大计数器,从0到2 ^ 80但在数组内部。

我想举个例子。具有两个字节的uint8_t数组:

| 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 */

}

您如何访问数字n并将内容复制到您的数组?

memcpy(array, &n, 10) ?

6 个答案:

答案 0 :(得分:2)

至少在这个宇宙中,你想要做的事是不可能的。

所有80位组合与最多2⁸⁰的所有数字相同 - 这是非常大数字。

正如您已经注意到的那样,这些值中的每一个都将具有10B的内存需求 - 总计

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

或换句话说,这是大约5.5万亿SSD,每个容量为2太字节。

让每个SSD重约80g,然后这相当于439,804,651吨的质量。

因为你有点顽固:即使你没有将它存储在RAM或磁盘上,也不可能完成:这里是你的&图表#34; N字节数组中的二进制组合&#34;问题。请注意,y轴的单位为10 ^ 28。

Number of Operations vs Array length

并且因为它没有实际帮助,使用对数y轴:

logarithmic scale

假设您的PC每秒可以通过十亿个这样的阵列,这就是它需要花费的时间:

Years wasted on generating the arrays

因此,对于七字节数组,只需生成数组并立即丢弃它们将花费两年多的时间。你的10 B阵列需要大约3800万年的CPU时间。祝你好运!

无论如何,递归是最糟糕的算法选择,你可以采用for循环并计算。这里没有歧义,这将与GMP完美配合。我不知道你做错了什么。学习使用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现在获取所有可能的2 ^ 80个值,并以二进制形式打印。从理论上讲。

答案 1 :(得分:2)

您可以使用类似下面的代码。

但请记住,效率不高。如果您想获得更好的性能,请使用unsigned long long s。

数组

替代解决方案是使用现有的库,如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?");
}

答案 2 :(得分:1)

这是未经检查的,未经优化的代码,有点运气可能会做你想要的。

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;
  }
}

答案 3 :(得分:1)

快速而肮脏的C解决方案:

#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;
}

不要期待看到这个节目的结束。

答案 4 :(得分:1)

这是非常可行的。你需要:

  1. 用于存储字节的数组。
  2. 增加字节的方法。
  3. 超出字节范围时携带溢出的方法。
  4. 这一切都可以在一个功能中完成。在最坏的情况下,堆栈只需要递归到字节数(10个字节= 10个堆栈递归)。

    这是我之前准备的。它支持任意数量的字节,尽管它只使用三个字节来让自己看到它运行到最后。

    "true"

答案 5 :(得分:0)

这是解决问题的简单方法,打印每个数字的二进制等效值。

尽管已经提出了一些解决方案,但我的是打印二进制的解决方案,它是递归的。

#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)));
}