Last active
December 30, 2015 22:09
-
-
Save pichi/7892725 to your computer and use it in GitHub Desktop.
Generating "binary code" (see http://stackoverflow.com/q/20422126/49197)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdlib.h> | |
#include <stdint.h> | |
#include <stdio.h> | |
enum { | |
max_k = 6, // it can't be bigger than 6 because it has to fit in 64 bit set | |
}; | |
typedef uint64_t set; | |
typedef unsigned char number; // 1 << max_k has to fit | |
static inline set set_n(set set, number n) { return set | (1ULL << n); } | |
static inline int is_set(set set, number n) { return (set & (1ULL << n)) != 0; } | |
static inline char *num2str(char *s, int k, number n) { | |
unsigned char *end = s += k; | |
*s-- = 0; // terminate string, just for debugging and doesn't matter | |
for(; k; k--, n >>= 1) | |
*s-- = '0' + (n & 1); // make '0'/'1' string backwards | |
return end; | |
} | |
// unsafe - doesn't add terminator, calloc does | |
static inline char *add_zero(char *s) { *s++ = '0'; return s; } | |
static inline char *add_one(char *s) { *s++ = '1'; return s; } | |
static inline number combs(int k) { return 1 << k; } | |
static inline number max_comb(int k) { return combs(k) - 1; } | |
static inline size_t codelen(int k) { return combs(k) + k - 1; } | |
static void gen(int k) { | |
char *code = calloc(codelen(k) + 1, sizeof(char)); | |
set s = 0; | |
number n, mask = max_comb(k); // max_comb(k) is mask with k set bits | |
// buf points to position in current code | |
void gen_(char *buf, set s, int rest, number x) { | |
if(rest) { | |
x = (x << 1) & mask; | |
if(!is_set(s, x)) | |
gen_(add_zero(buf), set_n(s, x), rest - 1, x); | |
x |= 1; | |
if(!is_set(s, x)) | |
gen_(add_one(buf), set_n(s, x), rest - 1, x); | |
} | |
else { // done, assume calloc clears memory so terminator is already there | |
puts(code); | |
} | |
} | |
for(n = 0; n < combs(k); n++) | |
gen_(num2str(code, k, n), set_n(s, n), combs(k) - 1, n); | |
free(code); | |
} | |
int usage(const char *name) { | |
fprintf(stderr, "Usage: %s k\n\nk has to be number from 1 up to %d\n", name, max_k); | |
return EXIT_FAILURE; | |
} | |
int main(int argc, const char* argv[] ) { | |
const char *name = argv[0]; | |
char *tmp, str[10]; | |
int i; | |
if(argc != 2) return usage(name); | |
i = strtol(argv[1], &tmp, 10); | |
if(*tmp != '\0' || i < 1 || i > max_k) return usage(name); | |
gen(i); | |
return EXIT_SUCCESS; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
First version is attempt to solve it without recursion. But gcc seems doing amazing work to optimize recursive code so recursive version is about 10% faster.