Day 14/C: Add bignum version
This commit is contained in:
parent
4a6bfff4c0
commit
e753594336
1 changed files with 108 additions and 0 deletions
108
14/solution_bignum.c
Normal file
108
14/solution_bignum.c
Normal file
|
@ -0,0 +1,108 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <gmp.h>
|
||||
|
||||
/* we can pack the pairs into integers… */
|
||||
#define P(a,b) (( (a-'A')<<6 )| (b-'A'))
|
||||
|
||||
/* …and use them as keys for a lookup table */
|
||||
enum {maxk=P('Z'+1,'Z')};
|
||||
MP_INT counts[maxk], tcounts[maxk];
|
||||
|
||||
void pcounts(int c) {
|
||||
int i,k;
|
||||
MP_INT min,max,n;
|
||||
mpz_init(&min);
|
||||
mpz_init(&max);
|
||||
mpz_init(&n);
|
||||
for(i='A';i<='Z';i++) {
|
||||
k=P(i,'z');
|
||||
mpz_set(&n, &counts[k]);
|
||||
if (mpz_cmp_ui(&n,0)){
|
||||
if (!mpz_cmp_ui(&min,0))
|
||||
mpz_set(&min,&n);
|
||||
if (mpz_cmp(&n, &min) < 0) mpz_set(&min,&n);
|
||||
else if (mpz_cmp(&n, &max) > 0) mpz_set(&max,&n);
|
||||
}
|
||||
}
|
||||
mpz_sub(&n, &max, &min);
|
||||
char *r = mpz_get_str(NULL, 10, &n);
|
||||
size_t rlen = strlen(r);
|
||||
if (rlen > 20)
|
||||
printf("%d iterations: %lu digits %.10s...%s\n", c, rlen, r, r+(rlen-10));
|
||||
else
|
||||
printf("%d iterations: %s\n", c, r);
|
||||
free(r);
|
||||
mpz_clear(&min);
|
||||
mpz_clear(&max);
|
||||
mpz_clear(&n);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
char tmpl[128], rules[128][3]={0};
|
||||
int i,j,k, maxiter=40;
|
||||
MP_INT n;
|
||||
|
||||
if (argc > 1)
|
||||
sscanf(argv[1], "%d",&maxiter);
|
||||
|
||||
mpz_init(&n);
|
||||
for(i=0;i<maxk;i++){
|
||||
mpz_init(&counts[i]);
|
||||
mpz_init(&tcounts[i]);
|
||||
}
|
||||
|
||||
scanf("%127[A-Z]\n", tmpl);
|
||||
for(i=0;tmpl[i];i++){
|
||||
/* set initial counts for pairs and single chars */
|
||||
if(i)
|
||||
mpz_add_ui(&counts[P(tmpl[i-1],tmpl[i])],&counts[P(tmpl[i-1],tmpl[i])], 1);
|
||||
/* use the same LUT for both */
|
||||
mpz_add_ui(&counts[P(tmpl[i],'z')],&counts[P(tmpl[i],'z')], 1);
|
||||
}
|
||||
|
||||
for(i=0;scanf("%c%c -> %c\n",
|
||||
&rules[i][0], &rules[i][1], &rules[i][2])==3;i++);
|
||||
|
||||
for(i=0;i<maxiter;i++) {
|
||||
/* reset temp LUT */
|
||||
for(j=0;j<maxk;j++){
|
||||
mpz_set_ui(&tcounts[j],0);
|
||||
}
|
||||
|
||||
/* apply each rule */
|
||||
for(j=0;rules[j][0];j++) {
|
||||
k=P(rules[j][0],rules[j][1]);
|
||||
mpz_set(&n, &counts[k]);
|
||||
|
||||
if (mpz_cmp_ui(&n,0)) {
|
||||
mpz_set_ui(&counts[k],0);
|
||||
/* single chars can be updated here */
|
||||
k=P(rules[j][2],'z');
|
||||
mpz_add(&counts[k],&counts[k], &n);
|
||||
/* pairs must be counted independently */
|
||||
k=P(rules[j][0],rules[j][2]);
|
||||
mpz_add(&tcounts[k],&tcounts[k],&n);
|
||||
k=P(rules[j][2],rules[j][1]);
|
||||
mpz_add(&tcounts[k],&tcounts[k],&n);
|
||||
}
|
||||
}
|
||||
|
||||
/* commit temp results */
|
||||
for(j=0;rules[j][0];j++) {
|
||||
k=P(rules[j][0],rules[j][2]);
|
||||
mpz_set(&counts[k], &tcounts[k]);
|
||||
k=P(rules[j][2],rules[j][1]);
|
||||
mpz_set(&counts[k], &tcounts[k]);
|
||||
}
|
||||
|
||||
if (i==maxiter-1) {
|
||||
pcounts(i+1);
|
||||
} else if (!((i+1)%500)) {
|
||||
printf("\033[G%.0f%\033[G",((i+1.0)/maxiter)*100);
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
mpz_clear(&n);
|
||||
}
|
Loading…
Reference in a new issue