/* @(#) $Revision: 1.8 $ */ /* @(#) RCS control in //prime.corp/usr/local/src/cmd/prime/src/mapstat.c */ /* * mapstat - give stats of a pair of kamps * * usage: * mapstat setname [setname2 ...] * * setname setname, path is setname/setname * * The state of the sieve comes in several files: * * setname/setname.neg array of bits bit x represents (low_k+x)*2^n-1 * 1 => composite, 0 => unknown * setname/setname.pos array of bits bit x represents (low_k+x)*2^n+1 * 1 => composite, 0 => unknown * * If several path/setname's are given, they are assumed to all have the * same low_k, n and size. A final status output is produced on the * computed logical or of all of the setname.neg and a report on the * computed logical or of all * of the setname.pos files. * * These files were prepaired by init_sieve. * * Given a set of 't' values: * * ** NOTE: we will use ^ to mean exponentiation ** * * {low_k*2^n-1, (low_k+1)*2^n-1, ... (low_k+k_len-1)*2^n-1} * {low_k*2^n+1, (low_k+1)*2^n+1, ... (low_k+k_len-1)*2^n+1} */ /* * * Copyright (C) 1997 Landon Curt Noll, all rights reserved. * * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose is hereby granted, provided that * the above copyright, this permission notice, and the disclaimer * below appear in all of the following: * * * supporting documentation * * source copies * * source works derived from this source * * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. * * Landon Curt Noll /\oo/\ * * chongo@{toad,sgi}.com Share and Enjoy! */ #include #include #include /* * popcnt - popcnt[x] number of 1 bits in 0 <= x < 256 */ char popcnt[256] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 }; /* * bit map of k*2^n-1 and k*2^n+1 values * * neg[y]&(1<<(x-1)) == 1 ==> (low_k + 8*y + x)*2^n-1 is composite * neg[y]&(1<<(x-1)) == 0 ==> (low_k + 8*y + x)*2^n-1 is unknown * * pos[y]&(1<<(x-1)) == 1 ==> (low_k + 8*y + x)*2^n+1 is composite * pos[y]&(1<<(x-1)) == 0 ==> (low_k + 8*y + x)*2^n+1 is unknown */ char *total_neg; /* logical or of all neg files read */ char *total_pos; /* logical or of all pos files read */ int total_len; /* length of both total_xyz buffers */ #define SETNAME_LEN 512 /* length of setname */ char setname[SETNAME_LEN+1]; /* name of state set */ char *program; /* our name */ /* * forward declarations */ int parse_kmap(char*, char**, int); void buf_stat(char*, char*, char*, int); main(argc, argv) int argc; /* arg count */ char *argv[]; /* the args */ { int len; /* error code or map length */ char *neg; /* current setname neg map file */ char *pos; /* current setname pos map file */ char *p; int i; int j; /* * parse args */ program = argv[0]; if (argc < 2) { fprintf(stderr, "usage: %s path/setname [path2/setname2 ...]\n", program); exit(1); } /* * process each arg */ for (j=1; j < argc; ++j) { /* * note the path of setname/setname */ p = strrchr(argv[j], '/'); p = ((p == NULL) ? argv[j] : p+1); if (strlen(argv[j]) + strlen(p) + 1 > SETNAME_LEN) { fprintf(stderr, "%s: setname is too long: %d\n", program, argv[j]); exit(2); } sprintf(setname, "%s/%s", argv[j], p); /* * read name.neg kmap file */ len = parse_kmap(setname, &neg, -1); if (len < 0) { fprintf(stderr, "%s: bad parse of %s.neg, return: %d\n", program, setname, len); exit(3); } /* * read name.pos kmap file */ i = parse_kmap(setname, &pos, +1); if (i < 0) { fprintf(stderr, "%s: bad parse of %s.pos, return: %d\n", program, setname, i); exit(4); } if (i != len) { fprintf(stderr, "%s: %s.neg length: %d != %s.pos length: %d\n", program, setname, len, setname, i); exit(5); } /* * produce the stats on the buffers */ buf_stat(setname, neg, pos, len); /* * We keep the first buffer set. We or in and free all * the other sets */ if (j == 1) { total_neg = neg; total_pos = pos; total_len = len; } else if (len == total_len) { /* or this map into the total map */ for (i=0; i < len; ++i) { total_neg[i] |= neg[i]; total_pos[i] |= pos[i]; } /* free these buffers */ free(neg); free(pos); } else { /* mismatched lengths */ fprintf(stderr, "%s:%s map length:%d != prev map length:%d\n", program, setname, len, total_len); exit(6); } } /* * produce total stats */ buf_stat("Total", total_neg, total_pos, total_len); free(total_neg); free(total_pos); /* * all done */ exit(0); } /* * parse_kmap - parse the name/name.neg or name.pos kmap file * * These files contain the bit maps of k values. * * neg[y]&(1<<(x-1)) == 1 ==> (low_k + 8*y + x)*2^n-1 is composite * neg[y]&(1<<(x-1)) == 0 ==> (low_k + 8*y + x)*2^n-1 is unknown * * pos[y]&(1<<(x-1)) == 1 ==> (low_k + 8*y + x)*2^n+1 is composite * pos[y]&(1<<(x-1)) == 0 ==> (low_k + 8*y + x)*2^n+1 is unknown * * given: * name name of state set * kmap malloced kmap buffer * posneg 1 ==> read name.pos, -1 ==> read name.neg * * Returns the map size of <0 ==> error. */ int parse_kmap(char *name, char **kmap, int posneg) { FILE *stream; /* file stream */ struct stat statbuf; /* status of the open file */ char filename[BUFSIZ+1]; /* filename holder */ /* * firewall */ if (posneg != 1 && posneg != -1) { fprintf(stderr, "%s: bad args to parse_kmap\n", program); return -1; } /* * open the file */ if (posneg == 1) { sprintf(filename, "%s.pos", name); } else { sprintf(filename, "%s.neg", name); } stream = fopen(filename, "r"); if (stream == NULL) { fprintf(stderr, "%s: cannot read %s\n", program, filename); if (posneg == 1) { perror("name.pos open"); } else { perror("name.neg open"); } return -2; } /* * obtain the size of the kmap */ if (fstat(fileno(stream), &statbuf) < 0) { fprintf(stderr, "%s: cannot stat %s\n", program, filename); if (posneg == 1) { perror("name.pos stat"); } else { perror("name.neg stat"); } return -3; } /* * malloc the kmap storage */ *kmap = (char *)malloc((long)(statbuf.st_size) * sizeof(char)); if (*kmap == NULL) { fprintf(stderr, "%s: malloc of %d bytes for %s kmap failed\n", program, (int)(statbuf.st_size), filename); if (posneg == 1) { perror("name.pos malloc"); } else { perror("name.neg malloc"); } return -5; } /* * read the kmap */ if (fread(*kmap, sizeof(char), (size_t)(statbuf.st_size), stream) != (int)(statbuf.st_size)) { fprintf(stderr, "%s: cannot read %s\n", program, filename); if (posneg == 1) { perror("name.pos fread"); } else { perror("name.neg fread"); } return -6; } /* * all done */ if (fclose(stream)) { fprintf(stderr, "%s: close error on %s\n", program, filename); if (posneg == 1) { perror("name.pos fclose"); } else { perror("name.neg fclose"); } return -7; } return (int)statbuf.st_size; } /* * buf_stat - calculcate stats on a neg and pso map buffer pair * * given: * setname name of state set * neg neg kmap buffer * pos pos kmap buffer * len length of buffer on octets */ void buf_stat(char *setname, char *neg, char *pos, int len) { int bitcnt; /* number of 1 bits found */ int i; /* * print name.neg map stats */ bitcnt = 0; for (i=0; i < len; ++i) { bitcnt += popcnt[neg[i]]; } printf("%s.neg: %d bits, %d 1s (%.2f%%), %d 0s (%.2f%%)\n", setname, len*8, bitcnt, ((double)bitcnt/(len*8.0))*100.0, (len*8 - bitcnt), 100.0-((double)bitcnt/(len*8.0))*100.0); /* * print name.pos map stats */ bitcnt = 0; for (i=0; i < len; ++i) { bitcnt += popcnt[pos[i]]; } printf("%s.pos: %d bits, %d 1s (%.2f%%), %d 0s (%.2f%%)\n", setname, len*8, bitcnt, ((double)bitcnt/(len*8.0))*100.0, (len*8 - bitcnt), 100.0-((double)bitcnt/(len*8.0))*100.0); /* * print name.neg ~or~ map.pos map stats * * I.e., print stats where either or both maps show a 1 bit */ bitcnt = 0; for (i=0; i < len; ++i) { bitcnt += popcnt[pos[i] | neg[i]]; } printf("%s.or: %d bits, %d 1s (%.2f%%), %d 0s (%.2f%%)\n", setname, len*8, bitcnt, ((double)bitcnt/(len*8.0))*100.0, (len*8 - bitcnt), 100.0-((double)bitcnt/(len*8.0))*100.0); /* * print name.neg ~xor~ map.pos map stats * * I.e., print stats where either but not both maps show a 1 bit */ bitcnt = 0; for (i=0; i < len; ++i) { bitcnt += popcnt[~(pos[i] ^ neg[i]) & 0xff]; } printf("%s.xor: %d bits, %d 1s (%.2f%%), %d 0s (%.2f%%)\n", setname, len*8, bitcnt, ((double)bitcnt/(len*8.0))*100.0, (len*8 - bitcnt), 100.0-((double)bitcnt/(len*8.0))*100.0); /* * print name.neg ~and~ map.pos map stats * * I.e., print stats where either but not both maps show a 1 bit */ bitcnt = 0; for (i=0; i < len; ++i) { bitcnt += popcnt[pos[i] & neg[i]]; } printf("%s.and: %d bits, %d 1s (%.2f%%), %d 0s (%.2f%%)\n", setname, len*8, bitcnt, ((double)bitcnt/(len*8.0))*100.0, (len*8 - bitcnt), 100.0-((double)bitcnt/(len*8.0))*100.0); /* * all done */ return; }