/* Test number palindromic by repeated addition Designed and implemented by John Walker in August 1987. */ #include #include #define STARTNUM 196 /* Starting number of sequence */ #define DIGITS 1200000 #define STOPAT 1000000 #define FALSE 0 #define TRUE 1 #define SIGNAL /* Checkpoint on Control C */ #define NICE /* Run at low priority */ #define CKTIME 7200 /* Auto-checkpoint every 2 hours */ extern char *malloc(); #ifdef TRACE #undef SIGNAL #endif #ifdef SIGNAL #include #endif static unsigned char *dig; /* Digits array */ static int ndig; /* Number of digits currently in array */ static int passes; /* Passes over number */ static int ckreq = FALSE; /* Checkpoint requested flag */ static int termreq = FALSE; /* Termination requested flag */ static FILE *console; /* CPOINT -- Checkpoint execution at current state. Valid only if additive pass is complete. */ static void cpoint() { int i, j; FILE *op; static int ckseq = 0; char tbfr[25]; long clk; struct tm *t; sprintf(tbfr, "%d.ck%d", STARTNUM, passes); ckseq = (ckseq + 1) % 10; op = fopen(tbfr, "w"); fprintf(op, "%d\n", passes); fprintf(op, "%d\n", ndig); j = 0; for (i = ndig - 1; i >= 0; i--) { if (j >= 70) { fprintf(op, "\n"); j = 0; } fprintf(op, "%d", dig[i] & 0xF); j++; } fprintf(op, "\n"); fclose(op); time(&clk); t = localtime(&clk); fprintf(console, "\n%02d:%02d Checkpoint %s pass %d, %d digits.\n", t->tm_hour, t->tm_min, tbfr, passes, ndig); ckreq = FALSE; } #ifdef SIGNAL /* PEEK -- Checkpoint if interrupt signal received. At every checkpoint the timed checkpoint is reset. Thus a manual checkpoint will automatically reschedule the timed checkpoint to that interval after the latest checkpoint. */ static void peek() { ckreq = TRUE; #ifdef CKTIME alarm(CKTIME); /* Reset timed checkpoint */ #endif } /* POKE -- Interrupt signal received to request termination. Set to checkpoint and shut down at the end. */ static void poke() { ckreq = TRUE; termreq = TRUE; } #endif /* MAIN -- Main program */ int main(argc, argv) int argc; char *argv[]; { register unsigned char *fp, *bp; register int i, j; int carry; FILE *op; #ifdef NICE nice(15); /* Switch to background batch priority */ #endif if ((dig = (unsigned char *) malloc(sizeof(unsigned char) * DIGITS)) == NULL) { fprintf(stderr, "Insufficient memory to allocate %d digit array\n", DIGITS); exit(-1); } /* Clear digits array and initialise to original number */ passes = 0; for (i = 0; i < DIGITS; i++) dig[i] = 0; /* If a file name is specified on the call statement, restart from a checkpoint file. */ if (argc > 1) { if ((op = fopen(argv[1], "r")) == NULL) { fprintf(stderr, "Cannot open checkpoint file.\n"); exit(-1); } fscanf(op, "%d", &passes); fscanf(op, "%d", &ndig); for (i = ndig - 1; i >= 0; i--) { while (TRUE) { j = fgetc(op); if (j == EOF) { fprintf(stderr, "Premature end of file in checkpoint file."); exit(-1); } if (j == '\n') continue; if (j < '0' || j > '9') { fprintf(stderr, "Illegal character %c in checkpoint file.", j); exit(-1); } dig[i] = j - '0'; break; } } while (TRUE) { j = fgetc(op); if (j == '\n') continue; if (j == EOF) break; fprintf(stderr, "Extra characters (%c) after end of checkpoint.\n", j); } fclose(op); fprintf(stderr, "\nRestart on pass %d, %d digits.\n", passes, ndig); } else { j = STARTNUM; ndig = 0; while (j) { dig[ndig++] = j % 10; j /= 10; } } if ((console = fopen("/dev/console", "w")) == NULL) console = stderr; #ifdef SIGNAL signal(SIGINT, poke); #endif #ifdef CKTIME signal(SIGALRM, peek); alarm(CKTIME); /* Wind the cat */ #endif /* Main loop */ while (TRUE) { /* Test existing number palindromic */ fp = dig; bp = dig + ndig - 1; i = ndig / 2; while (i > 0) { if (*fp++ != *bp--) break; i--; } if (i == 0) { printf("Number found palindromic on pass %d.\n", passes); printf("Number contains %d digits.\n", ndig); j = 0; for (i = ndig - 1; i >= 0; i--) { if (j >= 70) { printf("\n"); j = 0; } printf("%d", dig[i]); j++; } printf("\n"); op = fopen("pal.succ", "w"); fprintf(op, "%d\n", passes); fprintf(op, "%d\n", ndig); j = 0; for (i = ndig - 1; i >= 0; i--) { if (j >= 70) { fprintf(op, "\n"); j = 0; } fprintf(op, "%d", dig[i]); j++; } fprintf(op, "\n"); fclose(op); break; } #ifdef TRACE printf("Pass %d, %d digits: ", passes, ndig); j = 40; for (i = ndig - 1; i >= 0; i--) { if (j >= 70) { printf("\n"); j = 0; } printf("%d", dig[i]); j++; } printf("\n"); #endif /* Not palindromic. Perform next additive cycle. Note how we accumulate the resulting BCD number in the upper nybble of the 8 bit original number. */ fp = dig; bp = dig + ndig - 1; i = ndig; carry = 0; while (i > 0) { j = (*fp & 0xF) + (*bp-- & 0xF) + carry; *fp++ |= (j % 10) << 4; carry = j / 10; i--; } if (carry > 0) { /* Carry out of high order digit */ *fp = carry << 4; ndig++; } /* Shift the result down into the lower nybble */ fp = dig; i = ndig; while (i--) *fp++ = *fp >> 4; passes++; /* Test if digit array has overflowed. If so, checkpoint the solution. */ if (ndig >= DIGITS) { fprintf(console, "Digit array overflowed on pass %d.\n", passes); fprintf(console, "Number contains %d digits.\n", ndig); cpoint(); break; } if (ndig >= STOPAT) { fprintf(console, "Stop point reached on pass %d.\n", passes); fprintf(console, "Number contains %d digits.\n", ndig); cpoint(); break; } /* If the user has requested a checkpoint, do one. */ if (ckreq) cpoint(); /* If termination is requested, shut down. */ if (termreq) break; } return 0; }